标签:div 使用 状态 ++ 节点 ret oid 延迟 head
题目描述
输入
输出
样例输入
5 5
5 1 2 3 4
3 1
2 1
4 3
5 3
2 4 5
0 1 2
2 2 3
2 1 4
3 3 5
样例输出
3
2
2
invalid request!
题解
倍增LCA+dfs序+树状数组+主席树
维护一个dfs入栈出栈序,建立主席树,入栈位置将权值位置+1,出栈位置将权值位置-1.。
对于每个询问,转化为x->lca和y->lca的两条链,进而转化为4条路径:1~x + 1~y - 1~lca - 1~fa[lca]。
由于题目带修改,所以需要使用树状数组维护主席树的“前缀和”。然后就可以无脑码了。
需要注意的一点是本题卡空间,所以主席树的插入过程不能每次都新建节点,如果有节点就修改,没有再添加。
#include <cstdio> #include <algorithm> #define N 80010 using namespace std; int w[N] , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][18] , deep[N] , log[N] , lp[N] , rp[N] , num; int ls[N * 200] , rs[N * 200] , si[N * 200] , root[N << 1] , tot , A[40] , B[40] , C[40] , D[40] , ta , tb , tc , td; int v[N << 1] , tv , vk[N] , vx[N] , vy[N]; void add(int x , int y) { to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt; } void dfs(int x) { int i; lp[x] = ++num; for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1]; for(i = head[x] ; i ; i = next[i]) if(to[i] != fa[x][0]) fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]); rp[x] = ++num; } int lca(int x , int y) { int i; if(deep[x] < deep[y]) swap(x , y); for(i = log[deep[x] - deep[y]] ; ~i ; i -- ) if(deep[x] - deep[y] >= (1 << i)) x = fa[x][i]; if(x == y) return x; for(i = log[deep[x]] ; ~i ; i -- ) if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i]) x = fa[x][i] , y = fa[y][i]; return fa[x][0]; } void update(int p , int a , int l , int r , int &x) { if(!x) x = ++tot; si[x] += a; if(l == r) return; int mid = (l + r) >> 1; if(p <= mid) update(p , a , l , mid , ls[x]); else update(p , a , mid + 1 , r , rs[x]); } int query(int k , int l , int r) { if(l == r) return l; int mid = (l + r) >> 1 , sum = 0 , i; for(i = 1 ; i <= ta ; i ++ ) sum += si[rs[A[i]]]; for(i = 1 ; i <= tb ; i ++ ) sum += si[rs[B[i]]]; for(i = 1 ; i <= tc ; i ++ ) sum -= si[rs[C[i]]]; for(i = 1 ; i <= td ; i ++ ) sum -= si[rs[D[i]]]; if(k <= sum) { for(i = 1 ; i <= ta ; i ++ ) A[i] = rs[A[i]]; for(i = 1 ; i <= tb ; i ++ ) B[i] = rs[B[i]]; for(i = 1 ; i <= tc ; i ++ ) C[i] = rs[C[i]]; for(i = 1 ; i <= td ; i ++ ) D[i] = rs[D[i]]; return query(k , mid + 1 , r); } else { for(i = 1 ; i <= ta ; i ++ ) A[i] = ls[A[i]]; for(i = 1 ; i <= tb ; i ++ ) B[i] = ls[B[i]]; for(i = 1 ; i <= tc ; i ++ ) C[i] = ls[C[i]]; for(i = 1 ; i <= td ; i ++ ) D[i] = ls[D[i]]; return query(k - sum , l , mid); } } int main() { int n , q , i , j , x , y , f; scanf("%d%d" , &n , &q); for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &w[i]) , v[++tv] = w[i]; for(i = 2 ; i <= n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x) , log[i] = log[i >> 1] + 1; dfs(1); for(i = 1 ; i <= q ; i ++ ) { scanf("%d%d%d" , &vk[i] , &vx[i] , &vy[i]); if(!vk[i]) v[++tv] = vy[i]; } sort(v + 1 , v + tv + 1); for(tv = 0 , i = 1 ; i <= n + q ; i ++ ) if(v[i] != v[i - 1]) v[++tv] = v[i]; for(i = 1 ; i <= n ; i ++ ) { w[i] = lower_bound(v + 1 , v + tv + 1 , w[i]) - v; for(j = lp[i] ; j <= num ; j += j & -j) update(w[i] , 1 , 1 , tv , root[j]); for(j = rp[i] ; j <= num ; j += j & -j) update(w[i] , -1 , 1 , tv , root[j]); } for(i = 1 ; i <= q ; i ++ ) { if(vk[i]) { f = lca(vx[i] , vy[i]); if(deep[vx[i]] + deep[vy[i]] - 2 * deep[f] + 1 < vk[i]) puts("invalid request!"); else { ta = tb = tc = td = 0; for(j = lp[vx[i]] ; j ; j -= j & -j) A[++ta] = root[j]; for(j = lp[vy[i]] ; j ; j -= j & -j) B[++tb] = root[j]; for(j = lp[f] ; j ; j -= j & -j) C[++tc] = root[j]; for(j = lp[fa[f][0]] ; j ; j -= j & -j) D[++td] = root[j]; printf("%d\n" , v[query(vk[i] , 1 , tv)]); } } else { vy[i] = lower_bound(v + 1 , v + tv + 1 , vy[i]) - v; for(j = lp[vx[i]] ; j <= num ; j += j & -j) update(w[vx[i]] , -1 , 1 , tv , root[j]) , update(vy[i] , 1 , 1 , tv , root[j]); for(j = rp[vx[i]] ; j <= num ; j += j & -j) update(w[vx[i]] , 1 , 1 , tv , root[j]) , update(vy[i] , -1 , 1 , tv , root[j]); w[vx[i]] = vy[i]; } } return 0; }
【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树
标签:div 使用 状态 ++ 节点 ret oid 延迟 head
原文地址:http://www.cnblogs.com/GXZlegend/p/7413633.html