題目
正解
之前做ATCoder見過這樣的題,可是沒有看懂題解。
(不過這也似乎不是題解做法)
如果只有加法或者異或,那麼這題顯然是個水題。
隨便找一個點作爲根。修改某個點的時候,暴力修改它的父親,在自己身上打標記。詢問某個點的時候,結合自身的信息和父親身上的標記。
用專業的話來說,在每個點上維護一個權值,然後在父親上維護一個置換。用這個權值進行置換,就得到了真正的權值。
現在考慮去如何維護這個置換。
假如將所有的數拿出來從低位到高位建個,考慮操作之後會變得怎麼樣。異或顯然,加一相當於是一段連續的前綴變成,再後面一位變成(也就是變成這樣)。把這個操作對應到上的子樹,可以發現這其實就是這樣的過程:
從根節點開始,交換左右兒子,然後進入新的左兒子,繼續交換左右兒子,再進入新的左兒子……如此操作。
這樣可以發現一次加一操作的時間複雜度是的。至於異或,直接打標記就可以維護。
通過這個,可以維護置換和逆置換。
修改某個點上的值的時候,先通過父親上的求出其真實值,操作之後逆置換回去。
總的時間複雜度是
代碼
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;
}