2024-04-07
2024-04-07
上午模拟赛一道题都不会,摆摆摆
下午讲数学的人讲的就是一大坨,听不了一点
晚上改上次模拟赛剩下的一道题
xor on tree
树上的操作转化为 dfs 序上的操作
一个集合和某个数的异或的最大值可以用 01 trie 求
子树在 dfs 序上是一段区间,我们要进行的就是区间加入一个数
单点查询
但实际上我们区间插入的时候如果区间包含当前线段就直接 return 了
所以一个点的集合分散在线段树上一个叶子节点到根节点的路径上,往上边跳着求最大就行了
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1e5+10;
int n,m;
int w[N];
int root[N<<2];
vector<int> reuse;
struct Trie {
struct Node {
int son[2];
int cnt;
}tr[N*250];
int node;
void delet(int &u) {
if(tr[u].cnt) return;
tr[u].son[0]=tr[u].son[1]=0;
reuse.push_back(u);
u=0;
}
int newnode() {
if(!reuse.empty()) {
int p=reuse.back();
reuse.pop_back();
return p;
}
return ++node;
}
void update(int &u,int x,int t,int k) {
if(!u) {
u=newnode();
tr[u]={{0,0},0};
}
tr[u].cnt+=t;
if(k<0) {
delet(u);
return;
}
update(tr[u].son[(x>>k)&1],x,t,k-1);
delet(u);
}
int query(int u,int x,int k) {
if(!u||k<0) return 0;
int t=(x>>k)&1;
if(tr[u].son[!t]) return (1<<k)+query(tr[u].son[!t],x,k-1);
else return query(tr[u].son[t],x,k-1);
}
}trie;
vector<int> sn[N];
int dfn[N],siz[N],idt;
void dfs(int u) {
siz[u]=1,dfn[u]=++idt;
for(int i=0;i<sn[u].size();i++) {
int v=sn[u][i];
dfs(v);
siz[u]+=siz[v];
}
}
int pos[N];
#define ls (u<<1)
#define rs (u<<1|1)
void build(int u,int lft,int rgh) {
if(lft==rgh) {
pos[lft]=u;
return;
}
int mid=lft+rgh>>1;
build(ls,lft,mid),build(rs,mid+1,rgh);
}
void update(int u,int lft,int rgh,int l,int r,int v,int t) {
if(lft>=l&&rgh<=r) {
trie.update(root[u],v,t,30);
return;
}
int mid=lft+rgh>>1;
if(l<=mid) update(ls,lft,mid,l,r,v,t);
if(r>mid) update(rs,mid+1,rgh,l,r,v,t);
}
int query(int u,int v) {
int p=pos[u],res=0;
for(;p;p>>=1) res=max(res,trie.query(root[p],v,30));
return res;
}
int main() {
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int u=2;u<=n;u++) {
int fa;
scanf("%d",&fa);
sn[fa].push_back(u);
}
dfs(1);
build(1,1,n);
for(int i=1;i<=n;i++) update(1,1,n,dfn[i],dfn[i]+siz[i]-1,w[i],1);
for(int i=1;i<=m;i++) {
int opt;
scanf("%d",&opt);
if(opt==0) {
int k,x;
scanf("%d%d",&k,&x);
update(1,1,n,dfn[k],dfn[k]+siz[k]-1,w[k],-1);
w[k]=x;
update(1,1,n,dfn[k],dfn[k]+siz[k]-1,w[k],1);
}
else {
int k;
scanf("%d",&k);
printf("%d\n",query(dfn[k],w[k]));
}
}
return 0;
}
注意查询的时候要转化成
dfn[k]
今天就写了一道题,我太菜了……