【TJOI2018】 异或(可持久化01Trie+树链剖分)

传送门

【题目分析】

可持久化Trie与主席树其实没啥太大的实现上的差别,因为一次只会插入一个串,也就只会在前一个版本的Trie上改变一条链,那么其他儿子就可以与主席树类似的操作直接继承。

那么如何判断两个版本之间是否有一个串呢?我们对每个节点记一个size,只要后一个版本该节点的size>前一个版本该节点的size,那么就一定至少有一个串经过了当前节点。

有了这个东西我们就可以直接根据dfs序建立可持久化01Trie,第一个操作和第二个操作也就是树剖常规操作了。

(PS:Trie的空间一定要开够)

【代码~】

#include
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<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]]

 

你可能感兴趣的:(————数据结构————,树链剖分,Trie)