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