可持久化01Trie树+LCA【p4592】[TJOI2018]异或

Description

现在有一颗以\(1\)为根节点的由\(n\)个节点组成的树,树上每个节点上都有一个权值\(v_i\)。现在有\(Q\)次操作,操作如下:

  • 1\(\;x\;y\):查询节点\(x\)的子树中与\(y\)异或结果的最大值
  • 2\(\;x\;y\;z\):查询路径\(x\)\(y\)上点与\(z\)异或结果最大值

Input

第一行是两个数字\(n,Q\);

第二行是\(n\)个数字用空格隔开,第\(i\)个数字\(v_i\)表示点\(i\)上的权值

接下来\(n-1\)行,每行两个数,\(x,y\),表示节点\(x\)\(y\)之间有边

接下来\(Q\)行,每一行为一个查询,格式如上所述.

Output

对于每一个查询,输出一行,表示满足条件的最大值。

表示不太会可持久化\(01Trie\)

参考着题解码了出来,还是有点不懂.

但是又感觉懂得差不多。

这个题差不多可以自己码出来,很好的一个题。

可持久化\(01Trie\)思想还行,类似于主席树思想.

用到了\(lastroot\).

对于现在的自己,不太想深究具体构造,感觉网上讲解的这个不是很好。

打算活过\(NOIP\)之后写一篇讲解。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define R register

using namespace std;

const int maxn= 1e5+8;

inline void in(int &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}

struct Trie
{
	int root[maxn],ch[maxn*35][2],tot,cnt[maxn*35];
	Trie(){root[0]=tot=1;}
	inline void insert(int lastroot,int &nowroot,int x)
	{
		nowroot=++tot;
		int u=nowroot;
		for(R int i=30;~i;i--)
		{
			R int bit=(x>>i)&1;
			ch[u][!bit]=ch[lastroot][!bit];
			ch[u][bit]=++tot;
			u=ch[u][bit];
			lastroot=ch[lastroot][bit];
			cnt[u]=cnt[lastroot]+1;
		}
	}
	
	inline int query(int l,int r,int x)
	{
		int res=0;
		for(R int i=30;~i;i--)
		{
			R int bit=(x>>i)&1;
			if(cnt[ch[r][!bit]]-cnt[ch[l][!bit]])
			{
				r=ch[r][!bit];
				l=ch[l][!bit];
				res+=(1<<i);
			}
			else
			{
				r=ch[r][bit];
				l=ch[l][bit];
			}
		}
		return res;
	}
}tr,se;

int dfn[maxn],fdfn[maxn],val[maxn],idx,depth[maxn];

int head[maxn],tot,l[maxn],r[maxn],size[maxn];
struct cod{int u,v;}edge[maxn<<1];

inline void add(R int x,R int y)
{
	edge[++tot].u=head[x];
	edge[tot].v=y;
	head[x]=tot;
}

int f[maxn][21];

void dfs(R int u,R int fa)
{
	tr.insert(tr.root[fa],tr.root[u],val[u]);
	f[u][0]=fa;depth[u]=depth[fa]+1;
	dfn[u]=++idx,fdfn[idx]=u;size[u]=1;
	for(R int i=1;(1<<i)<=depth[u];i++)
		f[u][i]=f[f[u][i-1]][i-1];
	for(R int i=head[u];i;i=edge[i].u)
	{
		if(edge[i].v==fa)continue;
		dfs(edge[i].v,u);
		size[u]+=size[edge[i].v];
	}
}

inline int lca(R int x,R int y)
{
	if(depth[x]>depth[y])swap(x,y);
	for(R int i=17;~i;i--)
		if(depth[x]+(1<<i)<=depth[y])
			y=f[y][i];
	if(x==y)return y;
	for(R int i=17;~i;i--)
	{
		if(f[x][i]==f[y][i])continue;
		x=f[x][i],y=f[y][i];
	}
	return f[x][0];
}

int n,q;

int main()
{
	in(n),in(q);
	for(R int i=1;i<=n;i++)in(val[i]);
	for(R int i=1,x,y;i<n;i++)
	{
		in(x),in(y);
		add(x,y),add(y,x);
	}
	dfs(1,0);
	for(R int i=1;i<=n;i++)
		se.insert(se.root[i-1],se.root[i],val[fdfn[i]]);
	for(R int opt,x,y,z;q;q--)
	{
		in(opt);
		if(opt==1)
		{
			in(x),in(y);
			printf("%d\n",se.query(se.root[dfn[x]-1],se.root[dfn[x]+size[x]-1],y));
		}
		else
		{
			in(x),in(y),in(z);
			int la=lca(x,y);
			printf("%d\n",max(tr.query(tr.root[f[la][0]],tr.root[x],z),tr.query(tr.root[f[la][0]],tr.root[y],z)));
		}
	}
}
posted @ 2018-10-30 16:09  顾z  阅读(344)  评论(0编辑  收藏  举报