【TJOI2018】 異或(可持久化01Trie+樹鏈剖分)

傳送門

【題目分析】

可持久化Trie與主席樹其實沒啥太大的實現上的差別,因爲一次只會插入一個串,也就只會在前一個版本的Trie上改變一條鏈,那麼其他兒子就可以與主席樹類似的操作直接繼承。

那麼如何判斷兩個版本之間是否有一個串呢?我們對每個節點記一個size,只要後一個版本該節點的size>前一個版本該節點的size,那麼就一定至少有一個串經過了當前節點。

有了這個東西我們就可以直接根據dfs序建立可持久化01Trie,第一個操作和第二個操作也就是樹剖常規操作了。

(PS:Trie的空間一定要開夠)

【代碼~】

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int MAXM=2e5+10;
const int MAXP=5e6+10;

int n,q,cnt;
int a[MAXN];
int head[MAXN],fa[MAXN],son[MAXN],siz[MAXN],depth[MAXN],top[MAXN];
int nxt[MAXM],to[MAXM];
int dfn[MAXN],tot;
int rt[MAXN],sonn[MAXP][2],sizz[MAXP],total;

inline char nc(){
	static char buf[100000],*p1=buf,*p2=buf;
	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),(p1==p2))?EOF:*p1++;
}
#define getchar nc
inline int Read(){
	int i=0,f=1;
	char c=getchar();
	for(;(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())  i=(i<<3)+(i<<1)+c-'0';
	return i*f;
}

void add(int x,int y){
	nxt[++cnt]=head[x];
	head[x]=cnt;
	to[cnt]=y;
}

void insert(int &root,int last,int num){
	root=++total;
	sizz[root]=sizz[last]+1;
	int now=root;
	for(int i=30;i!=-1;--i){
		int k=(num>>i)&1;
		sonn[now][k^1]=sonn[last][k^1];
		sonn[now][k]=++total;
		sizz[sonn[now][k]]=sizz[sonn[last][k]]+1;
		now=sonn[now][k],last=sonn[last][k];
	}
}

int query(int rt1,int rt2,int num){
	int ret=0;
	for(int i=30;i!=-1;--i){
		int k=(num>>i)&1;
		if(sizz[sonn[rt2][k^1]]>sizz[sonn[rt1][k^1]])  ret|=(1<<i),rt1=sonn[rt1][k^1],rt2=sonn[rt2][k^1];
		else  rt1=sonn[rt1][k],rt2=sonn[rt2][k];
	}
	return ret;
}

void dfs1(int u,int f){
	siz[u]=1;
	for(int i=head[u];i!=-1;i=nxt[i]){
		int v=to[i];
		if(v==f)  continue;
		fa[v]=u;
		depth[v]=depth[u]+1;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])  son[u]=v;
	}
}

void dfs2(int u,int tp){
	top[u]=tp;
	dfn[u]=++tot;
	insert(rt[tot],rt[tot-1],a[u]);
	if(!son[u])  return ;
	dfs2(son[u],tp);
	for(int i=head[u];i!=-1;i=nxt[i]){
		int v=to[i];
		if(v==fa[u]||v==son[u])  continue;
		dfs2(v,v);
	}
}

int query_path(int x,int y,int k){
	int ret=0;
	while(top[x]!=top[y]){
		if(depth[top[x]]<depth[top[y]])  swap(x,y);
		ret=max(ret,query(rt[dfn[top[x]]-1],rt[dfn[x]],k));
		x=fa[top[x]];
	}
	if(depth[x]<depth[y])  swap(x,y);
	ret=max(ret,query(rt[dfn[y]-1],rt[dfn[x]],k));
	return ret;
}

signed main(){
	memset(head,-1,sizeof(head));
	n=Read(),q=Read();
	for(int i=1;i<=n;++i)  a[i]=Read();
	for(int i=1;i<n;++i){
		int x=Read(),y=Read();
		add(x,y),add(y,x);
	}
	dfs1(1,-1),dfs2(1,1);
	while(q--){
		int cz=Read(),x=Read(),y=Read();
		if(cz==1)  cout<<query(rt[dfn[x]-1],rt[dfn[x]+siz[x]-1],y)<<'\n';
		else{
			int k=Read();
			cout<<query_path(x,y,k)<<'\n';
		}
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章