P4592 [TJOI2018]异或
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
#else
startTime = clock(); //计时开始
freopen("in.txt","r",stdin);
#endif
}
void Time_test(){
#ifdef ONLINE_JUDGE
#else
endTime = 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
#else
startTime = clock(); //计时开始
freopen("in.txt","r",stdin);
#endif
}
void Time_test(){
#ifdef ONLINE_JUDGE
#else
endTime = 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[cP4592 [TJOI2018]异或 树链剖分 01trie