6714. 【2020.06.10省選模擬】題2 樹

題目


正解

之前做ATCoder見過這樣的題,可是沒有看懂題解。
(不過這也似乎不是題解做法)

如果只有加法或者異或,那麼這題顯然是個水題。
隨便找一個點作爲根。修改某個點的時候,暴力修改它的父親,在自己身上打標記。詢問某個點的時候,結合自身的信息和父親身上的標記。

用專業的話來說,在每個點上維護一個權值,然後在父親上維護一個置換。用這個權值進行置換,就得到了真正的權值。
現在考慮去如何維護這個置換。
假如將所有的數拿出來從低位到高位建個TrieTrie,考慮操作之後會變得怎麼樣。異或顯然,加一相當於是一段連續的前綴11變成00,再後面一位變成11(也就是1110...1110...變成0001...0001...這樣)。把這個操作對應到TrieTrie上的子樹,可以發現這其實就是這樣的過程:
從根節點開始,交換左右兒子,然後進入新的左兒子,繼續交換左右兒子,再進入新的左兒子……如此操作。
這樣可以發現一次加一操作的時間複雜度是O(lg1e9)O(\lg 1e9)的。至於異或,直接打標記就可以維護。

通過這個TrieTrie,可以維護置換和逆置換。
修改某個點上的值的時候,先通過父親上的TrieTrie求出其真實值,操作之後逆置換回去。

總的時間複雜度是O(nlgn)O(n \lg n)


代碼

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章