hdu4757 (可持久化Trie)
题目大意:给你一颗n个点的树,每个点有一个权值。然后有m个询问,问从x到y的简单路径中,权值 xor z最大是多少。
首先异或最大就是在字典树上找它的按位取反,首先满足高位。
思路:可持久化的0-1字典树,每个点在父节点的历史版本上新建一棵字典树,字典树上的每个结点给一个值记录从这个结点到树的根节点,有多少个权值会经过这个字典树上的结点。询问的时候在字典树上奏即可。由于a[i]<2^16,那么字典树的深度最大为16,空间复杂度为O(16 * n)。
算法理解:
首先ch[0][0],ch[0][1],v[0]的值一直是0,表示没有!
插入时:如果父节点中没有要找的值会y转向0结点!而x每次都会转向新建结点!(0结点是公共结点)
注意:结点从1开始,0结点用作没有值时的转向结点!
//#pragma comment(linker, "/STACK:102400000") #include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<list> #include<queue> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define pb push_back #define mp make_pair #define ULL unsigned long long #define LL long long #define inf 0x7fffffff #define eps 1e-7 #define N 100009 using namespace std; int m,n,T,t,x,y,u; int val[N]; vector<int>g[N]; int p[N][19],c[N]; int v[2000000],ch[2000000][2],sz,root[N]; const int mc=19; void init() { sz=1; memset(p,-1,sizeof(p)); for (int i=0; i<=n; ++i ) g[i].clear(); } int newnode() { memset(ch[sz],0,sizeof(ch[sz])); v[sz]=0; return sz++; } void insert(int x,int y,int z) { for(int i=15; i>=0; i--) { int c=(z>>(i))&1;//WA,只能取0,1 ch[x][c]=newnode(); ch[x][!c]=ch[y][!c]; v[ch[x][c]]=v[ch[y][c]]; x=ch[x][c],y=ch[y][c]; v[x]++; } } void dfs(int u,int fa) { p[u][0]=fa,c[u]=c[fa]+1; for(int i=1; i<mc&&p[u][i-1]!=-1; i++) p[u][i]=p[p[u][i-1]][i-1]; root[u]=newnode(); insert(root[u],root[fa],val[u]); for(int i=0; i<g[u].size(); i++) { int v=g[u][i]; if(v!=fa) { dfs(v,u); } } } int lca(int a,int b) { if(c[a]>c[b]) swap(a,b); int t=c[b]-c[a]; for(int i=0; i<mc&&t; i++) if(t&(1<<i)) { b=p[b][i]; t^=(1<<i); } if(a!=b) { for(int i=mc-1; i>=0; i--) if(p[a][i]!=p[b][i]) a=p[a][i],b=p[b][i]; a=p[a][0]; } return a; } int query(int x,int y,int f,int s) { int res=val[f]^s; f=root[f],x=root[x],y=root[y]; int ans=0;//f会变值 for(int i=15; i>=0; i--) { int c=!((s>>(i))&1); if(v[ch[x][c]]+v[ch[y][c]]-v[ch[f][c]]*2>0) ans|=(1<<i); else c=!c; x=ch[x][c],y=ch[y][c],f=ch[f][c]; } return max(ans,res); } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif int ncase=0; while(scanf("%d%d",&n,&m)==2) { init(); for(int i=1; i<=n; i++) scanf("%d",&val[i]); for(int i=1; i<n; i++) { scanf("%d%d",&x,&y); g[x].pb(y); g[y].pb(x); } c[0]=0; dfs(1,0);//父亲节点必须是0! while(m--) { int s; scanf("%d%d%d",&x,&y,&s); int fa=lca(x,y); printf("%d\n",query(x,y,fa,s)); } } return 0; }