题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=2588
题解:
主席树,在线,(求LCA)
感觉主席树真的好厉害。。。
在原树上建主席树。
即对于原树的节点 u ,它所对应的线段树维护的是原树中它到根的路径上的点的权值信息。
即建主席树时, u 的线段树是由 fa[u] 的线段树而来的。
然后对于询问的两个点 a,b,
得到其 LCA,记为 c,并令 d = fa[c]
那么 a 到 b 路径上的信息即为
a 对应的线段树 + b 对应的线段树 - c 对应的线段树 - d 对应的线段树
所以在主席树中直接查询第 K 小就好了。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 100500 #define filein(x) freopen(#x".in","r",stdin) #define fileout(x) freopen(#x".out","w",stdout) using namespace std; int A[MAXN],tmp[MAXN],bgs[MAXN],top[MAXN],dep[MAXN],fa[MAXN]; int N,M,tnt; struct Edge{ int to[MAXN*2],nxt[MAXN*2],head[MAXN],ent; void Reset(){ ent=2; memset(head,0,sizeof(head)); } void Adde(int u,int v){ to[ent]=v; nxt[ent]=head[u]; head[u]=ent++; to[ent]=u; nxt[ent]=head[v]; head[v]=ent++; } }E; struct CMT{ int rt[MAXN],ls[MAXN*20],rs[MAXN*20],cnt[MAXN*20],sz; void Insert(int &u,int l,int r,int p){ sz++; ls[sz]=ls[u]; rs[sz]=rs[u]; cnt[sz]=cnt[u]; u=sz; cnt[u]++; if(l==r) return; int mid=(l+r)>>1; if(p<=mid) Insert(ls[u],l,mid,p); else Insert(rs[u],mid+1,r,p); } int Query(int a,int b,int c,int d,int l,int r,int K){ if(l==r) return l; int mid=(l+r)>>1,lcnt=cnt[ls[a]]+cnt[ls[b]]-cnt[ls[c]]-cnt[ls[d]]; if(K<=lcnt) return Query(ls[a],ls[b],ls[c],ls[d],l,mid,K); else return Query(rs[a],rs[b],rs[c],rs[d],mid+1,r,K-lcnt); } }DT; void read(int &x){ static int f; static char ch; x=0; f=1; ch=getchar(); while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x=x*f; } void dfs1(int u,int dad){ static int num[MAXN]; DT.rt[u]=DT.rt[dad]; DT.Insert(DT.rt[u],1,tnt,A[u]); num[u]=1; fa[u]=dad; int bgn=0; for(int i=E.head[u],v;i;i=E.nxt[i]){ v=E.to[i]; if(v==dad) continue; dfs1(v,u); num[u]+=num[v]; if(num[v]<=bgn) continue; bgs[u]=v; bgn=num[v]; } } void dfs2(int u,int tp){ top[u]=tp; dep[u]=dep[fa[u]]+1; if(bgs[u]) dfs2(bgs[u],tp); for(int i=E.head[u],v;i;i=E.nxt[i]){ v=E.to[i]; if(v==fa[u]||v==bgs[u]) continue; dfs2(v,v); } } int lca(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]>dep[top[v]]) swap(u,v); v=fa[top[v]]; } if(dep[u]>dep[v]) swap(u,v); return u; } void solve(){ int lastANS=0,a,b,c,d,rta,rtb,rtc,rtd,K,p; for(int i=1;i<=M;i++){ read(a); read(b); read(K); a^=lastANS; c=lca(a,b); d=fa[c]; rta=DT.rt[a]; rtb=DT.rt[b]; rtc=DT.rt[c]; rtd=DT.rt[d]; p=DT.Query(rta,rtb,rtc,rtd,1,tnt,K); lastANS=tmp[p]; printf("%d",lastANS); if(i!=M) printf(" "); } } int main(){ E.Reset(); read(N); read(M); for(int i=1;i<=N;i++) read(A[i]),tmp[i]=A[i]; sort(tmp+1,tmp+N+1); tnt=unique(tmp+1,tmp+N+1)-tmp-1; for(int i=1;i<=N;i++) A[i]=lower_bound(tmp+1,tmp+tnt+1,A[i])-tmp; for(int i=1,u,v;i<N;i++) scanf("%d%d",&u,&v),E.Adde(u,v); dfs1(1,0); dfs2(1,1); solve(); return 0; }