Description
Input
Output
题解:
树套树.
之前做过不带修改的,感觉还挺容易的.
这次是带修改版本,就不能直接在树上建主席树了.
不同的是,我们对 $DFS$ 序建立主席树
考虑到每一次修改一个点,只会对该点的子树到根的路径产生影响.
在 DFS 序中,每个点的子树是一段连续的区间,直接用带修改主席树修改一波即可.
在 DFS 序中,每个点到根节点的路径和就是该点在 DFS 序中的前缀和.
这样进行修改和查询即可.
Code:
#include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout) #define maxn 200000 #define N 180000 using namespace std; int n,q, edges,cc,num; //权值线段树 namespace Seg { #define mid ((l+r)>>1) int rt[maxn],node[10][maxn],cnt[10]; int tot; struct Node { int l,r,w; }t[maxn*50]; void insert(int &x,int l,int r,int k,int delta) { if(!x) x=++tot; t[x].w+=delta; if(l==r) return; if(k<=mid) insert(t[x].l,l,mid,k,delta); else insert(t[x].r,mid+1,r,k,delta); } int lowbit(int t) { return t & (-t); } void update(int pos,int val,int delta) { while(pos<=N) insert(rt[pos],1,N,val,delta),pos+=lowbit(pos); } int query(int l,int r,int kth) { if(l==r) return l; int sum=0; for(int i=1;i<=cnt[0];++i) sum+=t[t[node[0][i]].r].w; for(int i=1;i<=cnt[1];++i) sum+=t[t[node[1][i]].r].w; for(int i=1;i<=cnt[2];++i) sum-=t[t[node[2][i]].r].w; for(int i=1;i<=cnt[3];++i) sum-=t[t[node[3][i]].r].w; if(sum < kth) { for(int i=1;i<=cnt[0];++i) node[0][i] = t[node[0][i]].l; for(int i=1;i<=cnt[1];++i) node[1][i] = t[node[1][i]].l; for(int i=1;i<=cnt[2];++i) node[2][i] = t[node[2][i]].l; for(int i=1;i<=cnt[3];++i) node[3][i] = t[node[3][i]].l; return query(l,mid,kth-sum); } else { for(int i=1;i<=cnt[0];++i) node[0][i] = t[node[0][i]].r; for(int i=1;i<=cnt[1];++i) node[1][i] = t[node[1][i]].r; for(int i=1;i<=cnt[2];++i) node[2][i] = t[node[2][i]].r; for(int i=1;i<=cnt[3];++i) node[3][i] = t[node[3][i]].r; return query(mid+1,r,kth); } } // 关键字 : 位置 int Query(int a,int b,int c,int d,int kth) { cnt[0]=cnt[1]=cnt[2]=cnt[3]=0; for(int i=a;i>0;i-=lowbit(i)) node[0][++cnt[0]] = rt[i]; for(int i=b;i>0;i-=lowbit(i)) node[1][++cnt[1]] = rt[i]; for(int i=c;i>0;i-=lowbit(i)) node[2][++cnt[2]] = rt[i]; for(int i=d;i>0;i-=lowbit(i)) node[3][++cnt[3]] = rt[i]; return query(1,N,kth); } }; struct Query { int opt,a,b; }Q[maxn]; int hd[maxn],to[maxn],nex[maxn],dfs[maxn],arr[maxn],A[maxn]; int st[maxn],ed[maxn],F[20][maxn],dep[maxn],val[maxn]; void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } //read and diskreat void read() { scanf("%d%d",&n,&q); for(int i=1;i<=n;++i) scanf("%d",&val[i]),A[++cc]=val[i]; for(int i=1,a,b;i<n;++i) scanf("%d%d",&a,&b), add(a,b),add(b,a); for(int i=1;i<=q;++i) { scanf("%d%d%d",&Q[i].opt,&Q[i].a,&Q[i].b); if(Q[i].opt==0) A[++cc]=Q[i].b; } sort(A+1,A+1+cc); for(int i=1;i<=q;++i) if(Q[i].opt==0) Q[i].b=lower_bound(A+1,A+1+cc,Q[i].b)-A; for(int i=1;i<=n;++i) val[i] = lower_bound(A+1,A+1+cc,val[i])-A; } //求dfs序 void DFS(int u,int fa) { F[0][u]=fa, dep[u] = dep[fa] + 1; for(int i=1;i<20;++i) F[i][u]=F[i-1][F[i-1][u]]; dfs[++num]=val[u],st[u]=num; for(int i=hd[u];i;i=nex[i]) { if(to[i]==fa) continue; DFS(to[i],u); } ed[u]=num+1; } int LCA(int a,int b) { if(dep[b]<dep[a]) swap(a,b); if(dep[a]!=dep[b]) { for(int i=19;i>=0;--i) if(dep[F[i][b]] >= dep[a]) b = F[i][b]; } if(a==b) return a; for(int i=19;i>=0;--i) { if(F[i][a]!=F[i][b]) a = F[i][a], b = F[i][b]; } return F[0][a]; } int main() { // setIO("input"); read(); DFS(1,0); for(int i = 1;i <= n; ++i) { Seg::update(st[i],val[i], 1); Seg::update(ed[i],val[i], -1); } for(int i=1,a,b;i<=q;++i) { a = Q[i].a, b = Q[i].b; if(Q[i].opt==0) { Seg::update(st[a], val[a], -1); Seg::update(ed[a], val[a], 1); val[a] = b; Seg::update(st[a],val[a], 1); Seg::update(ed[a],val[a], -1); } if(Q[i].opt>0) { int lca = LCA(a,b); int c = Seg::Query(st[a],st[b],st[lca],st[F[0][lca]],Q[i].opt); if(c==1) printf("invalid request!\n"); else printf("%d\n",A[c]); } } return 0; }