BZOJ 10628 Luogu2633——count on a tree
题意:查询一定区间内第K小的点权。
由于有lastans所以强制在线,这道题就相当于树上的主席树,
树链剖分+主席树,主席树相比普通主席树有一丢丢的改变,
root[i]不再是指向root[i-1],而是指向它在树上的父亲,
维护的序列是它到根节点的这条路径。
所以在求区间第k小时,可以用前缀和的思想加上lca,
val[u]+val[v]-val[lca]-val[fa[lca]],
得出的是lca分别到u和v的这两条路径中每个节点的数出现的次数。
然后用二分思想,跟普通主席树一样,二分直至l==r。
#include#include #include #include using namespace std; int size[100005]={0},fa[100005]={0},son[100005]={0},top[100005],dep[100005]={0},ls[100005*20],rs[100005*20],val[100005*20],root[100005],sz,v[100005], head[100005*2]={0},t=0,a[100002]={0},tot=0,real[100005]={0},dfn[100005]={0},num,cnt=0,pai[100005]; struct hh {int u,v,next; }e[200005]; void add(int x,int y) { t++; e[t].u=x; e[t].v=y; e[t].next=head[x]; head[x]=t; } void dfs(int now,int anc) { int i; top[now]=anc; tot++; dfn[now]=tot; real[tot]=now; if(son[now]==-1) return; dfs(son[now],anc); for(i=head[now];i!=0;i=e[i].next) { int v=e[i].v; if(v!=fa[now]&&v!=son[now]) dfs(v,v); } } void build(int u) { size[u]=1; for(int i=head[u];i!=0;i=e[i].next) { int v=e[i].v; if(v!=fa[u]) { dep[v]=dep[u]+1; fa[v]=u; build(v); size[u]=size[u]+size[v]; if(son[u]==-1||size[v]>size[son[u]]) son[u]=v; } } } int getlca(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) { swap(x,y); } x=fa[top[x]]; } if(dep[x]<dep[y]) { swap(x,y); } return y; } void insert(int &p,int cmp,int x,int l,int r){ p=++cnt;ls[p]=ls[cmp];rs[p]=rs[cmp];val[p]=val[cmp]+1; if(l!=r){ int mid=(l+r)/2; if(x<=mid){ insert(ls[p],ls[cmp],x,l,mid); } else{ insert(rs[p],rs[cmp],x,mid+1,r); } } } int query(int l,int r,int k){ int a=l,b=r,c=getlca(a,b),d=fa[c],mid,all; a=root[dfn[a]];b=root[dfn[b]];c=root[dfn[c]];d=root[dfn[d]]; l=1,r=sz; while(l<r){ mid=(l+r)>>1; all=val[ls[a]]+val[ls[b]]-val[ls[c]]-val[ls[d]]; if(all>=k){ r=mid;a=ls[a];b=ls[b];c=ls[c];d=ls[d]; } else{ l=mid+1;a=rs[a];b=rs[b];c=rs[c];d=rs[d];k-=all; } } return v[l]; } void jian(int &p,int l,int r){ p=++cnt; if(l!=r){ int mid=(l+r)/2; jian(ls[p],l,mid); jian(rs[p],mid+1,r); } } int main() { int c,b,k,p,i,x,y,s,z,lastans=0; scanf("%d%d",&num,&p); for(i=0;i<=num*4;i++) son[i]=-1; for(i=1;i<=num;i++) { scanf("%d",&a[i]); } for(i=1;i<=num-1;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dep[1]=1; build(1); dfs(1,1); for(i=1;i<=num;i++){ v[i]=pai[i]=a[i]; } sort(v+1,v+num+1); sz=unique(v+1,v+num+1)-v-1; jian(root[0],1,sz); for(i=1;i<=num;i++){ pai[i] = lower_bound(v + 1, v + 1 + sz, a[i]) - v; } for(i=1;i<=num;i++){ int t=real[i]; insert(root[i],root[dfn[fa[t]]],pai[t],1,sz); } while(p--){ scanf("%d%d%d",&c,&b,&k); c=c^lastans; lastans=query(c,b,k); printf("%d\n",lastans); } return 0; }