bzoj2588: Spoj 10628. Count on a tree 主席树
在每一个点的父亲做主席树,每次访问时用两个点的和减去其LCA和LCA父亲的和即可。
#include<bits/stdc++.h> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();} return x*f; } int q[101000],a[101000],fa[101000],n,m,len=0,dd,lin[101000],cnt=0,p[100100][23],hash[101000],l[2500000],r[2500000],sum[2500000],d[101000],root[101000]; bool f[101000]; struct one { int y,next; }; one e[201000]; void insert(int xx,int yy) { e[++len].next=lin[xx]; lin[xx]=len; e[len].y=yy; } int maketree(int L,int R) { int rt=++len; sum[rt]=0; if(L<R) { int mid=(L+R)>>1; l[rt]=maketree(L,mid); r[rt]=maketree(mid+1,R); } return rt; } int lca(int x,int y) { if(d[x]>d[y])swap(x,y); int ff=d[y]-d[x]; for(int i=0;(1<<i)<=n;i++) { if((1<<i)&ff)y=p[y][i]; } if(x==y)return x; for(int i=log2(n);i>=0;i--) if(p[x][i]!=p[y][i]){x=p[x][i];y=p[y][i];} x=p[x][0]; return x; } int update(int pre,int L,int R,int x) { int rt=++len; sum[rt]=sum[pre]+1;l[rt]=l[pre];r[rt]=r[pre]; if(L<R) { int mid=(L+R)>>1; if(x<=mid)l[rt]=update(l[pre],L,mid,x); else r[rt]=update(r[pre],mid+1,R,x); } return rt; } void init() { q[1]=1;int head=0,tail=1; f[1]=true; while(head++<tail) { int tn=q[head];int x=lower_bound(hash+1,hash+dd+1,a[tn])-hash; root[tn]=update(root[fa[tn]],1,dd,x); for(int i=lin[tn];i;i=e[i].next) { if(f[e[i].y])continue; f[e[i].y]=true;fa[e[i].y]=tn; p[e[i].y][0]=tn; d[e[i].y]=d[tn]+1; q[++tail]=e[i].y; } } for(int i=1;i<=22;i++) { for(int j=1;j<=n;j++) { p[j][i]=p[p[j][i-1]][i-1]; } } } int query(int x,int y,int LCA,int faLCA,int L,int R,int k) { int f1=sum[l[x]]-sum[l[faLCA]]+sum[l[y]]-sum[l[LCA]]; if(L>=R)return L; int mid=(L+R)>>1; if(k<=f1)return query(l[x],l[y],l[LCA],l[faLCA],L,mid,k); else return query(r[x],r[y],r[LCA],r[faLCA],mid+1,R,k-f1); } int work(int x,int y,int k) { int LCA=lca(x,y); return query(root[x],root[y],root[LCA],root[fa[LCA]],1,dd,k); } int main() { //freopen("xf.in","r",stdin); //freopen("xf.out","w",stdout); n=read();m=read(); int x,y,k; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); hash[i]=a[i]; } for(int i=1;i<n;i++) { x=read();y=read(); insert(x,y);insert(y,x); } len=0; sort(hash+1,hash+n+1); dd=unique(hash+1,hash+n+1)-hash-1; root[0]=maketree(1,dd); init(); int ans=0; for(int i=1;i<m;i++) { x=read(); x^=ans; y=read(); k=read(); ans=hash[work(x,y,k)]; printf("%d\n",ans); } x=read(); x^=ans; y=read(); k=read(); ans=hash[work(x,y,k)]; printf("%d",ans); return 0; }
注意最后一行不换行。