给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
鸣谢seter
大体思路就是对树上的每个点权进行离散化,然后对树上的的每一个节点到根的路径建一棵权值线段树,因为这些树形态结构都是相似的所有可以进行加减运算(主席树特性)。那么x,y两点之间的路径就可以表示成root[x]+root[y]-root[lca(x,y)]-root[fa[lca(x,y)],然后进行求解即可。
遇到的问题:直接对每一个节点建立的权值线段树,没有按照DFS序建树,于是RE了。为什么呢?因为在建树时是动态开点,也就是在他父亲所在的树上新开了一些节点,如果直接建树,有可能父亲节点还没有建,当前点就建立了。果然我还是太水了。。。。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 100003 #define M 6000000 using namespace std; int a1[N],p[N],b1[N],n,m; int v[N*2],point[N],next[N*2],tot; int fa[N][20],mi[20],deep[N],sz,cnt,num[N],pos[N]; int ls[M],rs[M],sum[M],root[N],nm,pd[N]; int cmp(int x,int y) { return a1[x]<a1[y]; } void add(int x,int y) { tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; } void dfs(int x,int f) { pos[x]=++sz; num[sz]=x; for (int i=1;i<=17;i++) { if (deep[x]-mi[i]<0) break; fa[x][i]=fa[fa[x][i-1]][i-1]; } for (int i=point[x];i;i=next[i]) if (v[i]!=f) { fa[v[i]][0]=x; deep[v[i]]=deep[x]+1; dfs(v[i],x); } } void build(int l,int r,int fa,int &k,int v) { k=++nm; ls[k]=ls[fa]; rs[k]=rs[fa]; int mid=(l+r)/2; sum[k]=sum[fa]+1; if (l==r) return ; if (v<=mid) build(l,mid,ls[fa],ls[k],v); else build(mid+1,r,rs[fa],rs[k],v); } int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); int k=deep[x]-deep[y]; for (int i=0;i<=17;i++) if ((k>>i)&1) x=fa[x][i]; if (x==y) return x; for (int i=17;i>=0;i--) if (fa[x][i]!=fa[y][i]) { x=fa[x][i]; y=fa[y][i]; } return fa[x][0]; } int query(int x,int y,int k) { int c=lca(x,y); int d=fa[c][0]; int l=1; int r=cnt; int a=root[pos[x]]; int b=root[pos[y]]; c=root[pos[c]]; d=root[pos[d]]; while (l<r) { int tmp=sum[ls[a]]+sum[ls[b]]-sum[ls[c]]-sum[ls[d]]; int mid=(l+r)/2; if (k<=tmp) { a=ls[a]; b=ls[b]; c=ls[c]; d=ls[d]; r=mid; } else { a=rs[a]; b=rs[b]; c=rs[c]; d=rs[d]; l=mid+1; k-=tmp; } } return a1[pd[l]]; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a1[i]),p[i]=i; sort(p+1,p+n+1,cmp); cnt=0; for (int i=1;i<=n;i++) if (a1[p[i]]!=a1[p[i-1]]) cnt++,b1[p[i]]=cnt,pd[cnt]=p[i]; else b1[p[i]]=cnt; for (int i=1;i<n;i++) { int x,y;scanf("%d%d",&x,&y); add(x,y); } deep[1]=1; mi[0]=1; for (int i=1;i<=17;i++) mi[i]=mi[i-1]*2; dfs(1,0); for (int i=1;i<=n;i++) { int t=num[i]; build(1,cnt,root[pos[fa[t][0]]],root[i],b1[t]); } int last=0; for (int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); x^=last; last=query(x,y,z); if (i!=m) printf("%d\n",last); else printf("%d",last); } }