题目
正解
之前做ATCoder见过这样的题,可是没有看懂题解。
(不过这也似乎不是题解做法)
如果只有加法或者异或,那么这题显然是个水题。
随便找一个点作为根。修改某个点的时候,暴力修改它的父亲,在自己身上打标记。询问某个点的时候,结合自身的信息和父亲身上的标记。
用专业的话来说,在每个点上维护一个权值,然后在父亲上维护一个置换。用这个权值进行置换,就得到了真正的权值。
现在考虑去如何维护这个置换。
假如将所有的数拿出来从低位到高位建个
T
r
i
e
Trie
Trie,考虑操作之后会变得怎么样。异或显然,加一相当于是一段连续的前缀
1
1
1变成
0
0
0,再后面一位变成
1
1
1(也就是
1110...
1110...
1110...变成
0001...
0001...
0001...这样)。把这个操作对应到
T
r
i
e
Trie
Trie上的子树,可以发现这其实就是这样的过程:
从根节点开始,交换左右儿子,然后进入新的左儿子,继续交换左右儿子,再进入新的左儿子……如此操作。
这样可以发现一次加一操作的时间复杂度是
O
(
lg
1
e
9
)
O(\lg 1e9)
O(lg1e9)的。至于异或,直接打标记就可以维护。
通过这个
T
r
i
e
Trie
Trie,可以维护置换和逆置换。
修改某个点上的值的时候,先通过父亲上的
T
r
i
e
Trie
Trie求出其真实值,操作之后逆置换回去。
总的时间复杂度是 O ( n lg n ) O(n \lg n) O(nlgn)
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 300010
#define M 500010
#define uint unsigned
#define bit 32
uint input(){
char ch=getchar();
while (ch<'0' || ch>'9')
ch=getchar();
uint x=0;
do{
x=x*10+ch-'0';
ch=getchar();
}
while ('0'<=ch && ch<='9');
return x;
}
uint output(uint x){
static uint st[20];
if (x==0)
putchar('0');
else{
int k=0;
for (;x;x/=10)
st[++k]=x%10;
for (;k;--k)
putchar('0'+st[k]);
}
}
int n,m,B;
uint a[N];
struct EDGE{
int to;
EDGE *las;
} e[N*4];
int ne;
EDGE *last[N];
int fa[N];
void init(int x){
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=fa[x])
fa[ei->to]=x,init(ei->to);
}
//(False) a[x] -> getp(rt[fa[x]],a[x]) (True)
struct Node *null;
Node *newnode();
struct Node{
Node *c[2];
bool isrev;
uint tag;
void rse(){
swap(c[0],c[1]);
isrev^=1;
}
void gt(uint _tag){tag^=_tag;}
void pd(){
if (tag&1)
rse();
if (tag>>1){
if (c[0]==null) c[0]=newnode();c[0]->gt(tag>>1);
if (c[1]==null) c[1]=newnode();c[1]->gt(tag>>1);
}
tag=0;
}
} d[M*70],*rt[N];
int cnt;
Node *newnode(){return &(d[++cnt]={null,null,0});}
uint getp(Node *t,uint x){
uint y=0;
for (int i=0;i<bit;++i){
t->pd();
uint w=x>>i&1;
y|=(w^t->isrev)<<i;
t=t->c[w^t->isrev];
}
return y;
}
uint getp_rev(Node *t,uint x){
uint y=0;
for (int i=0;i<bit;++i){
t->pd();
uint w=x>>i&1;
y|=(w^t->isrev)<<i;
t=t->c[w];
}
return y;
}
void trans_add(Node *t){
for (int i=0;i<bit;++i){
t->pd();
t->rse();
if (t->c[0]==null)
t->c[0]=newnode();
t=t->c[0];
}
}
void trans_xo(Node *t,int v){
t->gt(v);
}
void add(int x){
uint b=getp(rt[fa[x]],a[x]);
b++;
a[x]=getp_rev(rt[fa[x]],b);
}
void xo(int x,uint v){
uint b=getp(rt[fa[x]],a[x]);
b^=v;
a[x]=getp_rev(rt[fa[x]],b);
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n=input(),m=input();
for (int i=1;i<=n;++i)
a[i]=input();
for (int i=1;i<n;++i){
int u=input(),v=input();
e[ne]={v,last[u]};
last[u]=e+ne++;
e[ne]={u,last[v]};
last[v]=e+ne++;
}
init(1);
null=d;
*null={null,null,0};
for (int i=0;i<=n;++i)
rt[i]=newnode();
for (int i=1;i<=m;++i){
uint op=input(),x=input();
if (op==1)
output(getp(rt[fa[x]],a[x])),putchar('\n');
else if (op==2){
if (fa[x])
add(fa[x]);
trans_add(rt[x]);
}
else{
uint v=input();
if (fa[x])
xo(fa[x],v);
trans_xo(rt[x],v);
}
}
return 0;
}