来自FallDream的博客,未经允许,请勿转载,谢谢。
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。 n,m<=100000
题解:
查的是链,很容易想到树剖。然后我们按照dfs序建一棵主席树,每次询问找到最多log个根同时移动。期望复杂度nlogn(loglogn)
然后去百度了一下,学习了一个新姿势 树上主席树。每个点存一下它到根的路径上的权值,建树的时候直接可持久化,查询的时候直接用两个点的加起来减去lca处的就行了。复杂度是nlogn
讲道理这样会比树剖快,但是可能是数据原因,跑的没有树剖快qaq
两个的代码都贴一下
树剖+主席树
#include<iostream> #include<cstdio> #include<algorithm> #define mp(x,y) make_pair(x,y) #define MN 100000 #define ll long long using namespace std; inline ll read() { // int x;scanf("%lld",&x);return x; ll x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } ll last=0; int n,m,mx[MN+5],size[MN+5],dfn[MN+5],dn=0,cnt=0,dep[MN+5],tot=1; int a[MN+5],p[MN+5],head[MN+5],top[MN+5],fa[MN+5],rt[MN+5],tp,L[MN+5]; pair<int,int> q[MN+5]; struct node{int l,r,x;}T[MN*30]; struct edge{int to,next;}e[MN*2+5]; void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } void dfs1(int x,int f) { mx[x]=0;size[x]=1;fa[x]=f; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) { dep[e[i].to]=dep[x]+1;dfs1(e[i].to,x); size[x]+=size[e[i].to]; if(size[e[i].to]>size[mx[x]]) mx[x]=e[i].to; } } void dfs2(int x,int tp) { dfn[x]=++dn;p[dn]=x;top[x]=tp; if(mx[x]) dfs2(mx[x],tp); for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa[x]&&e[i].to!=mx[x]) dfs2(e[i].to,e[i].to); } void ins(int x,int nx,int k) { int l=1,r=tot,mid; while(l<r) { mid=l+r>>1; if(k<=mid) { T[nx].r=T[x].r;T[nx].l=++cnt; x=T[x].l;nx=T[nx].l;r=mid; } else { T[nx].l=T[x].l;T[nx].r=++cnt; x=T[x].r;nx=T[nx].r;l=mid+1; } T[nx].x=T[x].x+1; } } void getrt(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); q[++tp]=mp(rt[dfn[x]],rt[dfn[top[x]]-1]); x=fa[top[x]]; } if(dfn[x]>dfn[y]) swap(x,y); q[++tp]=mp(rt[dfn[y]],rt[dfn[x]-1]); } main() { n=read();m=read(); for(int i=1;i<=n;i++) L[i]=a[i]=read(); sort(L+1,L+n+1); for(int i=2;i<=n;i++) if(L[i]!=L[i-1]) L[++tot]=L[i]; for(int i=1;i<n;i++) { int u=read(),v=read(); ins(u,v); } cnt=0;dfs1(1,0);dfs2(1,1); for(int i=1;i<=n;i++) ins(rt[i-1],rt[i]=++cnt,(a[p[i]]=lower_bound(L+1,L+tot+1,a[p[i]])-L)); for(int i=1;i<=m;i++) { ll x=read()^last;int y=read(),k=read();tp=0; getrt(x,y); int l=1,r=tot,mid; while(l<r) { int sum=0;mid=l+r>>1; for(int j=1;j<=tp;j++) sum+=T[T[q[j].first].l].x-T[T[q[j].second].l].x; if(sum<k) { k-=sum;l=mid+1; for(int j=1;j<=tp;j++) q[j]=mp(T[q[j].first].r,T[q[j].second].r); } else { r=mid; for(int j=1;j<=tp;j++) q[j]=mp(T[q[j].first].l,T[q[j].second].l); } } printf("%lld",last=L[l]);if(i!=m) puts(""); } return 0; }
树上主席树
#include<iostream> #include<cstdio> #include<algorithm> #define MN 100000 #define MK 18 #define ll long long using namespace std; inline ll read() { ll x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } ll last=0; int n,m,cnt=0,dep[MN+5],tot=1,a[MN+5],head[MN+5],fa[MN+5][MK+2],rt[MN+5],L[MN+5]; struct node{int l,r,x;}T[MN*30]; struct edge{int to,next;}e[MN*2+5]; void ins(int f,int t) { e[++cnt]=(edge){t,head[f]};head[f]=cnt; e[++cnt]=(edge){f,head[t]};head[t]=cnt; } void dfs1(int x,int f) { fa[x][0]=f; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) dep[e[i].to]=dep[x]+1,dfs1(e[i].to,x); } void ins(int x,int nx,int k) { int l=1,r=tot,mid; while(l<r) { mid=l+r>>1; if(k<=mid) { T[nx].r=T[x].r;T[nx].l=++cnt; x=T[x].l;nx=T[nx].l;r=mid; } else { T[nx].l=T[x].l;T[nx].r=++cnt; x=T[x].r;nx=T[nx].r;l=mid+1; } T[nx].x=T[x].x+1; } } void init(int x) { ins(rt[fa[x][0]],rt[x]=++cnt,a[x]=lower_bound(L+1,L+tot+1,a[x])-L); for(int i=head[x];i;i=e[i].next) if(e[i].to!=fa[x][0]) init(e[i].to); } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j) if(k&1) x=fa[x][j]; if(x==y) return x; for(int i=MK;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) L[i]=a[i]=read(); sort(L+1,L+n+1); for(int i=2;i<=n;i++) if(L[i]!=L[i-1]) L[++tot]=L[i]; for(int i=1;i<n;i++) { int u=read(),v=read(); ins(u,v); } dfs1(1,0);cnt=0;init(1); for(int i=1;i<=MK;i++) for(int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; for(int i=1;i<=m;i++) { int x=(int)(read()^last),y=read(),k=read(),b; int l=1,r=tot,mid;int z=rt[b=lca(x,y)];x=rt[x];y=rt[y]; while(l<r) { mid=l+r>>1;int sum=T[T[x].l].x+T[T[y].l].x-2*T[T[z].l].x+(a[b]>=l&&a[b]<=mid); if(sum<k) k-=sum,x=T[x].r,y=T[y].r,z=T[z].r,l=mid+1; else x=T[x].l,y=T[y].l,z=T[z].l,r=mid; } printf("%lld",last=L[l]);if(i!=m) puts(""); } return 0; }