[TJOI2018]xor
题目大意:
有一棵树,根节点为1。每个点有点权。有两种操作。
1. 求节点x所在子树中点权与y异或的最大值。
2. 求x到y的路径上点权与z异或的最大值。
解题思路:
可持久化字典树。
对于第一种操作,我们对树进行dfs遍历,求出每个节点的dfs序(树剖),然后由于子树中dfs序连续,所以相当于区间的询问。对每个1~x区间建trie即可。
对于第二种操作,我们对每个节点建一颗trie,记录其到根的路径上的信息。
然后常规求LCA,减一减即可。
C++ Code:
#include<bits/stdc++.h> const int N=1e5+5; int ch[N<<6][2],siz[N<<6],ccnt=0,n,q,a[N],head[N],to[N<<1],nxt[N<<1]; int sz[N],dep[N],son[N],top[N],trie1[N],trie2[N],dfn[N],idfn[N],idx=0,fa[N],ans; inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } void Insert(int&nw,int&o,int&p,int pp=30){ nw=++ccnt; if(!~pp)return(void)(siz[nw]=siz[o]+1); ch[nw][0]=ch[o][0]; ch[nw][1]=ch[o][1]; int nxt=(p>>pp)&1; Insert(ch[nw][nxt],ch[o][nxt],p,pp-1); siz[nw]=siz[ch[nw][0]]+siz[ch[nw][1]]; } void dfs1(int now,int pre){ sz[now]=1; Insert(trie1[now],trie1[pre],a[now]); for(int i=head[now];i;i=nxt[i]) if(!dep[to[i]]){ dep[to[i]]=dep[now]+1; fa[to[i]]=now; dfs1(to[i],now); sz[now]+=sz[to[i]]; if(!son[now]||sz[to[i]]>sz[son[now]])son[now]=to[i]; } } void dfs2(int now){ idfn[dfn[now]=++idx]=now; if(son[now])top[son[now]]=top[now],dfs2(son[now]); for(int i=head[now];i;i=nxt[i]) if(to[i]!=son[now]&&dep[to[i]]>dep[now]) dfs2(top[to[i]]=to[i]); } inline int LCA(int x,int y){ while(top[x]!=top[y]) if(dep[top[x]]>=dep[top[y]])x=fa[top[x]];else y=fa[top[y]]; return dep[x]<dep[y]?x:y; } void query(int&R,int&L,int&num,int pp=30){ if(!~pp)return; int nw=(num>>pp)&1^1; if(siz[ch[R][nw]]>siz[ch[L][nw]]){ ans|=1<<pp; query(ch[R][nw],ch[L][nw],num,pp-1); }else query(ch[R][!nw],ch[L][!nw],num,pp-1); } void query2(int&x,int&y,int&lca,int&fa,int&num,int pp=30){ if(!~pp)return; int nw=(num>>pp)&1^1; if(siz[ch[x][nw]]+siz[ch[y][nw]]-siz[ch[lca][nw]]-siz[ch[fa][nw]]>0){ ans|=1<<pp; query2(ch[x][nw],ch[y][nw],ch[lca][nw],ch[fa][nw],num,pp-1); }else query2(ch[x][!nw],ch[y][!nw],ch[lca][!nw],ch[fa][!nw],num,pp-1); } int main(){ n=readint(),q=readint(); for(int i=1;i<=n;++i)a[i]=readint(); for(int i=1;i<n;++i){ int u=readint(),v=readint(); to[i<<1]=v;nxt[i<<1]=head[u]; head[u]=i<<1; to[i<<1|1]=u;nxt[i<<1|1]=head[v]; head[v]=i<<1|1; } memset(dep,0,sizeof dep); memset(son,0,sizeof son); dep[1]=1; dfs1(1,0); dfs2(1); for(int i=1;i<=n;++i) Insert(trie2[i],trie2[i-1],a[idfn[i]]); while(q--) if(readint()==1){ int x=readint(),y=readint(); ans=0;query(trie2[dfn[x]+sz[x]-1],trie2[dfn[x]-1],y); printf("%d\n",ans); }else{ int x=readint(),y=readint(),z=readint(); int lca=LCA(x,y); ans=0; query2(trie1[x],trie1[y],trie1[lca],trie1[fa[lca]],z); printf("%d\n",ans); } return 0; }