P4592 [TJOI2018]异或
题目描述
现在有一颗以1为根节点的由n个节点组成的树,树上每个节点上都有一个权值vi。现在有Q次操作,操作如下:
- 1 x y:查询节点x的子树中与y异或结果的最大值
- 2 x y z:查询路径x到y上点与z异或结果最大值
输入输出格式
输入格式:
第一行是两个数字n,Q;
第二行是n个数字用空格隔开,第i个数字vi表示点i上的权值
接下来n−1行,每行两个数,x,y,表示节点x与y之间有边
接下来Q行,每一行为一个查询,格式如上所述.
输出格式:
对于每一个查询,输出一行,表示满足条件的最大值。
输入输出样例
说明
对于10%的数据,有1<n,Q≤100
对于20%的数据,有1<n,Q≤1000
对于40%的数据,有1<n,Q≤10000
对于100%的数据,有1<n,Q≤100000
对于100%的数据,有查询1中的y≤230,查询2中的z≤230。
Solution:
本题可持久化trie树。
最大异或和都会吧,本题不过是把操作放到了树上罢了。
对于操作$1$:在子树中选取某一信息,明摆着dfs序弄出来,用可持久化trie树维护一下dfs序的节点权值,询问只要在子树的dfs序中贪心就好了。
对于操作$2$:查询树上路径,那么就跑lca嘛,用可持久化trie树自上而下维护根节点到每个节点的链的节点权值,对于询问$x,y$,在$s_x-s_{lca(x,y)-1}+s_y-s_{lca(x,y)}$的节点信息中贪心就好了。
代码:
/*Code by 520 -- 9.29*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; const int N=100005; int n,m,val[N],rt1[N],rt2[N],cnt1,cnt2; int fa[N][21],dep[N],to[N<<1],net[N<<1],h[N],ec; int inc[N],ouc[N],ppx; struct node{ int son[2],tot; }t1[N*80],t2[N*80]; int gi(){ int a=0;char x=getchar(); while(x<'0'||x>'9') x=getchar(); while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar(); return a; } il void add(int u,int v){to[++ec]=v,net[ec]=h[u],h[u]=ec;} void ins1(int &rt,int lst,int d,int v){ t1[rt=++cnt1]=t1[lst],t1[rt].tot++; if(d<0) return; int p=v&(1<<d)?1:0; ins1(t1[rt].son[p],t1[lst].son[p],d-1,v); } int query1(int l,int r,int d,int v,int ans){ if(d<0) return ans; int p=v&(1<<d)?1:0,ls=t1[t1[l].son[p^1]].tot,rs=t1[t1[r].son[p^1]].tot; if(rs-ls) return query1(t1[l].son[p^1],t1[r].son[p^1],d-1,v,ans|(1<<d)); return query1(t1[l].son[p],t1[r].son[p],d-1,v,ans); } void ins2(int &rt,int lst,int d,int v){ t2[rt=++cnt2]=t2[lst],t2[rt].tot++; if(d<0) return; int p=v&(1<<d)?1:0; ins2(t2[rt].son[p],t2[lst].son[p],d-1,v); } int query2(int lx,int rx,int ly,int ry,int d,int v,int ans){ if(d<0) return ans; int p=v&(1<<d)?1:0,ls=t2[t2[lx].son[p^1]].tot+t2[t2[ly].son[p^1]].tot,rs=t2[t2[rx].son[p^1]].tot+t2[t2[ry].son[p^1]].tot; if(rs-ls) return query2(t2[lx].son[p^1],t2[rx].son[p^1],t2[ly].son[p^1],t2[ry].son[p^1],d-1,v,ans|(1<<d)); return query2(t2[lx].son[p],t2[rx].son[p],t2[ly].son[p],t2[ry].son[p],d-1,v,ans); } void dfs(int u){ inc[u]=++ppx; ins1(rt1[inc[u]],rt1[inc[u]-1],30,val[u]); ins2(rt2[u],rt2[u],30,val[u]); for(RE int i=h[u];i;i=net[i]) if(to[i]!=fa[u][0]){ fa[to[i]][0]=u,dep[to[i]]=dep[u]+1,rt2[to[i]]=rt2[u]; dfs(to[i]); } ouc[u]=ppx; } il int lca(int x,int y){ if(dep[x]<dep[y]) swap(x,y); int dd=dep[x]-dep[y]; For(i,0,20) if(dd&(1<<i)) x=fa[x][i]; if(x==y) return x; Bor(i,0,20) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int main(){ n=gi(),m=gi(); For(i,1,n) val[i]=gi(); int opt,x,y,z,tp; For(i,1,n-1) x=gi(),y=gi(),add(x,y),add(y,x); dfs(1); For(j,1,20) For(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1]; while(m--){ opt=gi(),x=gi(),y=gi(); if(opt==1) printf("%d\n",query1(rt1[inc[x]-1],rt1[ouc[x]],30,y,0)); else { z=gi(),tp=lca(x,y); printf("%d\n",query2(rt2[fa[tp][0]],rt2[x],rt2[tp],rt2[y],30,z,0)); } } return 0; }
PS:~蒟蒻写博客不易,转载请注明出处,万分感谢!~