P4592 [TJOI2018]异或
题意:
现在有一颗以 1 为根节点的由 n 个节点组成的树,节点从 1 至 n 编号。树上每个节点上都有一个权值 vi。现在有 q 次操作,操作如下:
1 x z:查询节点 x 的子树中的节点权值与 z 异或结果的最大值。
2 x y z:查询节点 x 到节点 y 的简单路径上的节点的权值与 z 异或结果最大值。
题解:
很明显的可持久化01Trie
对于第一个问题,直接按照时间戳(DFS序)建立点权的可持久化01Trie,每次查询就是对区间[dfn[u],dfn[u]+siz[u]-1]的询问,(u的所有儿子都被包含在这个区间内)
关于第二个问题,我们都知道对于u->v的路径,我们可以拆分成rt到u,rt到v,rt到lca,rt到fa[lca](老套路了)这四套路径,建立rt到所有点的可持久化01Trie,然后查询这四条路找到答案
相当于对于两问建了两个可持久化01Trie
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){ll s=0,w=1ll;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
void rd_test(){#ifdef ONLINE_JUDGE#elsestartTime = clock(); //计时开始freopen("in.txt","r",stdin);#endif
}
void Time_test(){#ifdef ONLINE_JUDGE#elseendTime = clock(); //计时结束printf("\n运行时间为:%lfs\n",(double)(endTime - startTime) / CLOCKS_PER_SEC);#endif
}
int n,m,sum,dep[200001],a[200001],ktot,size[200001],tpos[200001],pre[200001],head[200001],tot,f[200001][25];
struct edge{int to,next;
}g[1000001];
inline void made(int from,int to){g[++tot].to=to;g[tot].next=head[from];head[from]=tot;
}
struct Trie{int n,son[10000001][2],cnt=1,sum,root[200001],ct[10000001];void ins(int &rt,int x,int T){ct[++cnt]=ct[rt]+1;son[cnt][0]=son[rt][0];son[cnt][1]=son[rt][1];rt=cnt;if (T==-1) return;register bool y=(x>>T)&1;ins(son[rt][y],x,T-1);}inline void insert(int pre,int rt,int x){root[rt]=root[pre];ins(root[rt],x,30);}int QUE(int i,int j,int x,int T){//序列版if (T==-1) return 0;register bool y=(x>>T)&1;if (ct[son[j][1^y]]>ct[son[i][1^y]]) return ((1<<T)+QUE(son[i][1^y],son[j][1^y],x,T-1));else return QUE(son[i][y],son[j][y],x,T-1);}int queryxx(int i,int j,int lca,int fa,int x,int T){//树上差分版if (T==-1) return 0;register bool y=(x>>T)&1;if (ct[son[j][1^y]]+ct[son[i][1^y]]>ct[son[lca][1^y]]+ct[son[fa][1^y]]) return ((1<<T)+queryxx(son[i][1^y],son[j][1^y],son[lca][1^y],son[fa][1^y],x,T-1));else return queryxx(son[i][y],son[j][y],son[lca][y],son[fa][y],x,T-1);}int queryx(int i,int j,int lc,int flc,int x,int T){return queryxx(root[i],root[j],root[lc],root[flc],x,T);}inline int query(int l,int r,int x){return QUE(root[l-1],root[r],x,30);}
}tr1,tr2;
void dfs0(int u,int fa){dep[u]=dep[fa]+1;f[u][0]=fa;tpos[u]=++ktot;pre[ktot]=u;tr1.insert(fa,u,a[u]);size[u]=1;for (int i=1;i<=21;i++) f[u][i]=f[f[u][i-1]][i-1];for (int i=head[u];i;i=g[i].next){int v=g[i].to;if (v==fa) continue;dfs0(v,u);size[u]+=size[v];}
}
inline int LCA(int x,int y){if (dep[x]<dep[y]) swap(x,y);for (int i=21;i>=0;i--){if (dep[f[x][i]]>=dep[y]) x=f[x][i];}if (x==y) return x;for (int i=21;i>=0;i--){if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];}return f[x][0];
}
int main(){rd_test();n=read();m=read();for (int i=1;i<=n;i++) a[i]=read();for (int i=1;i<n;i++){int x=read(),y=read();made(x,y);made(y,x);}dfs0(1,0);for (int i=1;i<=n;i++){tr2.insert(i-1,i,a[pre[i]]);}while (m--){int opt=read();if (opt==1){int x=read(),y=read();printf("%d\n",tr2.query(tpos[x],tpos[x]+size[x]-1,y));}else{int x=read(),y=read(),z=read();int lca=LCA(x,y);printf("%d\n",tr1.queryx(x,y,lca,f[lca][0],z,30));}}Time_test();
}
写的另一个还没改完的代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
//Fe~Jozky
clock_t startTime, endTime;
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){ll s=0,w=1ll;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
void rd_test(){#ifdef ONLINE_JUDGE#elsestartTime = clock(); //计时开始freopen("in.txt","r",stdin);#endif
}
void Time_test(){#ifdef ONLINE_JUDGE#elseendTime = clock(); //计时结束printf("\n运行时间为:%lfs\n",(double)(endTime - startTime) / CLOCKS_PER_SEC);#endif
}
const int maxn=3e5+9;
vector<int>vec[maxn];
struct tree{int cnt=0;int ch[3];
}tr[maxn*40];
int rt[maxn];
int a[maxn];
int fa[maxn][25], dep[maxn], lg[maxn];
int rtnum=0;
int dfn[maxn],predfn[maxn];
int dfnnum=0;
int siz[maxn];
int newa[maxn];
void insert(int now,int pre,int x){for(int i=30;i>=0;i--){int c=((x>>i)&1);tr[now].ch[c^1]=tr[pre].ch[c^1];tr[now].ch[c]=++rtnum;now=tr[now].ch[c];pre=tr[pre].ch[c];tr[now].cnt=tr[pre].cnt+1;}
}
int query(int L,int R,int x){int sum=0;for(int i=30;i>=0;i--){int c=((x>>i)&1);if(tr[tr[R].ch[c^1]].cnt>tr[tr[L].ch[c^1]].cnt){sum+=(1<<i);L=tr[L].ch[c^1];R=tr[R].ch[c^1]; }else {L=tr[L].ch[c];R=tr[R].ch[c]; }}return sum;
}
void dfs(int now,int fath){siz[now]=1;dep[now]=dep[fath]+1;fa[now][0]=fath;for(int i=1;(1<<i)<=dep[now];i++)fa[now][i]=fa[fa[now][i-1]][i-1];dfn[now]=++dfnnum;newa[dfnnum]=a[now];//predfn[dfnnum]=now;for(int i=0;i<vec[now].size();i++){if(vec[now][i]!=fath){dfs(vec[now][i],now);siz[now]+=siz[vec[now][i]];}}
}
int LCA(int x,int y){if(dep[x]<dep[y])swap(x,y);while(dep[x]>dep[y])x=fa[x][lg[dep[x]]-dep[y]];if(x==y)return x;for(int i=lg[dep[x]];i>=0;i--){if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}}return fa[x][0];
}
int main()
{rd_test(); int n,m;cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<n;i++){int u,v;cin>>u>>v;vec[u].push_back(v);vec[v].push_back(u);}lg[0]=-1;for(int i=1;i<=n;i++)lg[i]=lg[i>>1]+1;dfs(1,0);rt[0]=++rtnum;insert(rt[0],0,0);int tot=0;for(int i=1;i<=dfnnum;i++){tot^=newa[i];rt[i]=++rtnum;insert(rt[i],rt[i-1],tot);}for(int i=1;i<=m;i++){int op;scanf("%d",&op);int x,y,z;if(op==1){scanf("%d%d",&x,&z);int ans=query(rt[dfn[x]-1],rt[dfn[x]+siz[x]-1],z);printf("%d\n",ans);}else {scanf("%d%d%d",&x,&y,&z);if(dfn[x]>dfn[y])swap(x,y);int lca=LCA(x,y);//int ans=max(query(rt[dfn[lca]-1],rt[dfn[x]],z),query(rt[dfn[x]+siz[x]-1],rt[dfn[y]],z));cout<<"???"<<endl;}}Time_test();
}