首页 > 其他分享 >4545

4545

时间:2023-08-07 17:00:46浏览次数:29  
标签:lres int mn ++ fa kmax 4545

## Problem
给定一棵树和 $m$ 个询问,每个询问要求回答不在 $x$ 和 $y$ 两节点所形成的路径上的点的最小标号。
## Input 多组数据,EOF结束。
第一行两个整数 $n$ 和 $q$。($n,q \le 10^6$)
接下来 $n-1$ 行,每行两整数,表示树上的一条边。
接下来 $q$ 行,每行两个整数 $x$ 和 $y$。
询问强制在线,$x, y$ 要与上一次的结果进行异或操作(第一次询问则不操作)
## Output 对于每个询问,输出最小不在 $x$ 到 $y$ 的路径上的最小编号。
若所有点都在路径上,则输出 $n$
## Sample
#### Input 1 ```txt 4 1 1 2 1 3 1 4 2 3 5 2 1 2 1 3 2 4 2 5 1 2 7 6 ```
#### Output 1 ``` 4 3 1 ```
## Solution
首先容易发现一个性质,如果两点间的简单路径不经过 $1$ 号点,答案就是 $1$。我们将 $1$ 号点设为整棵树的根,然后分情况讨论。
1. 如果两点不经过 $1$,说明两点的 $Lca \neq 1$,由于数据范围较大,直接求 $Lca$ 可能会 TLE。不难发现两点一定属于 $1$ 的同一个子树内,于是遍历整棵树的时候记录下
代码: ```cpp #include <iostream> #include <cstdio> #include <cstring> #include <algorithm>
using namespace std;
const int kmax = 1e6 + 1; const int kmaxM = 21;
struct E {     int p, y; } e[kmax << 1];
int n, m; int h[kmax], ec; int mn[kmax][3]; int pr[kmax]; int d[kmax], f[kmax][kmaxM]; int l[kmax], r[kmax], idx; int lres;
void Getmin(int x, int v) {     if(v == mn[x][0] || v == mn[x][1] || v == mn[x][2] || v == x) return;     if(v < mn[x][0]) {         mn[x][2] = mn[x][1];         mn[x][1] = mn[x][0];         mn[x][0] = v;     } else if(v < mn[x][1]) {         mn[x][2] = mn[x][1];         mn[x][1] = v;     } else {         mn[x][2] = min(mn[x][2], v);     } }
void Dfs(int x, int fa) {     l[x] = ++idx;     d[x] = d[fa] + 1, f[x][0] = fa;     pr[x] = (fa == 0 ? -1 : (fa == 1 ? x : pr[fa]));     for(int i = 0; i < 3; i++) {         mn[x][i] = n;     }     for(int i = 1; i < kmaxM; i++) {         f[x][i] = f[f[x][i - 1]][i - 1];     }     for(int i = h[x]; i; i = e[i].p) {         int y = e[i].y;         if(y == fa) continue;         Dfs(y, x);         Getmin(x, min(y, mn[y][0]));     }     r[x] = idx; }
void Dfss(int x, int fa) {     for(int i = 0; i < 3; i++) {         Getmin(x, mn[fa][i]);     }     for(int i = h[x]; i; i = e[i].p) {         int y = e[i].y;         if(y == fa) continue;         Dfss(y, x);     } }
int Lca(int x, int y) {     if(d[x] > d[y]) swap(x, y);     for(int i = kmaxM - 1; ~i; i--) {         if(d[f[y][i]] >= d[x]) {             y = f[y][i];         }     }     for(int i = kmaxM - 1; ~i; i--) {         if(f[x][i] != f[y][i]) {             x = f[x][i];             y = f[y][i];         }     }     return x == y ? x : f[x][0]; }
void Addedge(int x, int y) {     e[++ec] = {h[x], y};     h[x] = ec; }
bool Son(int z, int x) {     if(z > n) return 0;     return l[z] <= l[x] && l[x] <= r[z]; }
void Solve() {     for(int i = 1, x, y; i < n; i++) {         cin >> x >> y;         Addedge(x, y);         Addedge(y, x);     }     Dfs(1, 0);     Dfss(1, 1); //  for(int i = 1; i <= n; i++) { //      cout << "i = " << i << ":\n"; //      for(int j = 0; j < 3; j++) { //          cout << mn[i][j] << ' '; //      } //      cout << '\n'; //  }     for(int i = 1, x, y, z, l; i <= m; i++) {         cin >> x >> y;         x ^= lres, y ^= lres;         if(pr[x] == pr[y]) {             lres = (x == 1) + 1;         } else {             lres = 1e9;             for(int j = 0; j < 3; j++) {                 z = mn[x][j];                 if(!Son(z, x) && !Son(z, y)) {                     lres = min(lres, z);                 } //              cout << z << '\n';                 z = mn[y][j];                 if(!Son(z, x) && !Son(z, y)) {                     lres = min(lres, z);                 } //              cout << z << '\n';             }         }         cout << lres << '\n';     } }
void Init() {     memset(h, 0, sizeof(h));     ec = idx = lres = 0; }
int main() {     ios::sync_with_stdio(0);     cin.tie(0), cout.tie(0);     while(cin >> n >> m) {         Init();         Solve();     }     return 0; } ```

标签:lres,int,mn,++,fa,kmax,4545
From: https://www.cnblogs.com/ereoth/p/17611878.html

相关文章