给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
N,M<=100000
一开始看了标签:嗯,主席树。那么一定就要放在序列上搞,dfs序。然后又是一条链,树链剖分,每次提取log个区间出来,就像树状数组套主席树一样。
然后就re了。
嗯,上界开小了,离散化。
T了。
题解:树上差分,维护点到根的主席树,维护四个根即可x,y,lca,fa[lca]。
然后就A了。
#include<map> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define re register const int maxn=100005; int n,m,a[maxn]; int cnt,head[maxn]; int fa[maxn][21],dep[maxn]; int root[maxn],ls[maxn*50],rs[maxn*50],sum[maxn*50]; struct edge{ int x,y,next; }e[maxn<<1]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch==‘-‘);ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x = f ? -x : x ; } void write(int x){ if(x>9) write(x/10); putchar(x%10+‘0‘); } void add(int x,int y){ e[++cnt]=(edge){x,y,head[x]}; head[x]=cnt; } void copy(int x,int y){ls[x]=ls[y];rs[x]=rs[y];sum[x]=sum[y];} int build(int rt,int l,int r,int pos){ int t=++cnt; copy(t,rt); sum[t]++; if(l==r) return t; int mid=(l+r)>>1; if(pos<=mid) ls[t]=build(ls[t],l,mid,pos); else rs[t]=build(rs[t],mid+1,r,pos); return t; } void dfs(int x){ root[x]=build(root[fa[x][0]],1,n,a[x]); for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for(int i=head[x];i;i=e[i].next){ int y=e[i].y; if(y==fa[x][0]) continue; fa[y][0]=x; dep[y]=dep[x]+1; dfs(y); } } int lca(int x,int y){ if(dep[x]>dep[y]) swap(x,y); int delt=dep[y]-dep[x]; for(int i=0;delt;i++,delt>>=1) if(delt&1) y=fa[y][i]; if(x==y) return x; for(int i=20;fa[x][0]!=fa[y][0];i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int query(int x1,int x2,int y1,int y2,int k){ int l=1,r=n; while(1){ if(l==r) return l; int ret=sum[ls[x1]]+sum[ls[x2]]-sum[ls[y1]]-sum[ls[y2]],mid=(l+r)>>1; if(ret>=k){ x1=ls[x1];x2=ls[x2];y1=ls[y1];y2=ls[y2]; r=mid; } else { x1=rs[x1];x2=rs[x2];y1=rs[y1];y2=rs[y2]; l=mid+1;k-=ret; } } } inline int query(int x,int y,int k){ int t=lca(x,y); return query(root[x],root[y],root[t],root[fa[t][0]],k); } int tot,b[maxn],cx[maxn]; int main(){ read(n);read(m); for(re int i=1;i<=n;i++) read(a[i]),b[++tot]=a[i]; sort(b+1,b+n+1); tot=unique(b+1,b+tot+1)-b-1; for(re int i=1;i<=n;++i){ int x=lower_bound(b+1,b+tot+1,a[i])-b; cx[x]=a[i]; a[i]=x; } for(re int i=1;i<n;++i){ int x,y; read(x);read(y); add(x,y);add(y,x); } cnt=0; dfs(1); int ans=0; while(m--){ int x,y,k; read(x);read(y);read(k); x^=ans; write(ans=cx[query(x,y,k)]); putchar(10); } }
不过讲道理,$O(nlog^{2}n)$也至于慢那么多(第一个点就60s,还是加了各种优化)。
然后关于静态k大
原文:https://www.cnblogs.com/sto324/p/11644488.html