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

本文详细解析了可持久化Trie与主席树的实现原理,通过记录节点大小来判断版本间是否有新增字符串,并介绍如何利用DFS序构建可持久化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';
		}
	}
}

 

洛谷P4592,请分析一下这段代码WA40pts的原因: #include <bits/stdc++.h> using namespace std; const int BITS = 32; const int MAX_N = 1e5 + 50; int n, q, val[MAX_N], fa[MAX_N], tim; int dep[MAX_N], siz[MAX_N], son[MAX_N]; int top[MAX_N], dfn[MAX_N], rev[MAX_N]; vector<int> e[MAX_N]; void dfs1(int u, int father, int depth) { fa[u] = father; dep[u] = depth; siz[u] = 1; for (int v : e[u]) { if (v == father) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int topf) { top[u] = topf; dfn[u] = ++tim; rev[tim] = u; if (son[u]) dfs2(son[u], topf); for (int v : e[u]) if (!dfn[v]) dfs2(v, v); } int root[MAX_N], tot; struct Node { int ch[2], cnt; Node() {ch[0] = ch[1] = cnt = 0; } } tr[MAX_N * BITS]; int insert(int pos, int x, int k) { int cur = ++tot, t = x >> k & 1; tr[cur] = tr[pos], tr[cur].cnt++; if (k < 0) return cur; tr[cur].ch[t] = insert(tr[cur].ch[t], x, k - 1); return cur; } int query(int u, int v, int x, int k) { if (k < 0) return 0; int t = x >> k & 1; if (tr[tr[v].ch[t ^ 1]].cnt - tr[tr[u].ch[t ^ 1]].cnt) return query(tr[u].ch[t ^ 1], tr[v].ch[t ^ 1], x, k - 1) + (1 << k); return query(tr[u].ch[t], tr[v].ch[t], x, k - 1); } int query(int l, int r, int x) { return query(root[l - 1], root[r], x, BITS - 1); } int tree_query(int x, int z) { return query(dfn[x], dfn[x] + siz[x] - 1, z); } int path_query(int x, int y, int z) { int ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); ans = max(ans, query(dfn[top[x]], dfn[x], z)); x = fa[top[x]]; } if (dep[x] < dep[y]) swap(x, y); ans = max(ans, query(dfn[y], dfn[x], z)); return ans; } int main() { cin >> n >> q; for (int i = 1; i <= n; i++) cin >> val[i]; for (int i = 1, u, v; i < n; i++) { cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dfs1(1, 0, 1); dfs2(1, 1); for (int i = 1; i <= n; i++) root[i] = insert(root[i - 1], val[rev[i]], BITS - 1); for (int opt, x, y, z; q--; ) { cin >> opt; if (opt == 1) { cin >> x >> z; cout << tree_query(x, z) << '\n'; } else { cin >> x >> y >> z; cout << path_query(x, y, z) << '\n'; } } return 0; }
最新发布
07-24
洛谷P4592 WA了,求原因:#include <bits/stdc++.h> using namespace std; const int BITS = 32; const int MAX_N = 1e5 + 50; int n, q, val[MAX_N], fa[MAX_N], tim; int dep[MAX_N], siz[MAX_N], son[MAX_N]; int top[MAX_N], dfn[MAX_N], rev[MAX_N]; vector<int> e[MAX_N]; void dfs1(int u, int father, int depth) { fa[u] = father; dep[u] = depth; siz[u] = 1; for (int v : e[u]) { if (v == father) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int topf) { top[u] = topf; dfn[u] = ++tim; rev[tim] = u; if (son[u]) dfs2(son[u], topf); for (int v : e[u]) if (!dfn[v]) dfs2(v, v); } int root[MAX_N], tot; struct Node { int ch[2], cnt; Node() {ch[0] = ch[1] = cnt = 0; } } tr[MAX_N * BITS]; int insert(int pos, int x, int k) { int cur = ++tot, t = x >> k & 1; tr[cur] = tr[pos], tr[cur].cnt++; if (k < 0) return cur; tr[cur].ch[t] = insert(tr[cur].ch[t], x, k - 1); return cur; } int query(int u, int v, int x, int k) { if (k < 0) return 0; int t = x >> k & 1; if (tr[tr[v].ch[t ^ 1]].cnt - tr[tr[u].ch[t ^ 1]].cnt) return query(tr[u].ch[t ^ 1], tr[v].ch[t ^ 1], x, k - 1) + (1 << k); return query(tr[u].ch[t], tr[v].ch[t], x, k - 1); } int query(int l, int r, int x) { return query(root[l - 1], root[r], x, BITS - 1); } int tree_query(int x, int z) { return query(dfn[x], dfn[x] + siz[x] - 1, z); } int path_query(int x, int y, int z) { int ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); ans = max(ans, query(dfn[top[x]], dfn[x], z)); x = fa[top[x]]; } if (dep[x] < dep[y]) swap(x, y); ans = max(ans, query(dfn[y], dfn[x], z)); return ans; } int main() { cin >> n >> q; for (int i = 1; i <= n; i++) cin >> val[i]; for (int i = 1, u, v; i < n; i++) { cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dfs1(1, 0, 1); dfs2(1, 1); for (int i = 1; i <= n; i++) root[i] = insert(root[i - 1], val[rev[i]], BITS - 1); for (int opt, x, y, z; q--; ) { cin >> opt; if (opt == 1) { cin >> x >> z; cout << tree_query(x, z) << '\n'; } else { cin >> x >> y >> z; cout << path_query(x, y, z) << '\n'; } } return 0; }
07-19
洛谷P4592WA40pts,分析一下原因: #include <bits/stdc++.h> using namespace std; const int BITS = 32; const int MAX_N = 1e5 + 50; int n, q, val[MAX_N], fa[MAX_N], tim; int dep[MAX_N], siz[MAX_N], son[MAX_N]; int top[MAX_N], dfn[MAX_N], rev[MAX_N]; vector e[MAX_N]; void dfs1(int u, int father, int depth) { fa[u] = father; dep[u] = depth; siz[u] = 1; for (int v : e[u]) { if (v == father) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int topf) { top[u] = topf; dfn[u] = ++tim; rev[tim] = u; if (son[u]) dfs2(son[u], topf); for (int v : e[u]) if (!dfn[v]) dfs2(v, v); } int root[MAX_N], tot; struct Node { int ch[2], cnt; Node() {ch[0] = ch[1] = cnt = 0; } } tr[MAX_N * BITS]; int insert(int pos, int x, int k) { int cur = tot, t = x >> k & 1; tr[cur] = tr[pos], tr[cur].cnt++; if (k < 0) return cur; tr[cur].ch[t] = insert(tr[cur].ch[t], x, k - 1); return cur; } int query(int u, int v, int x, int k) { if (k < 0) return 0; int t = x >> k & 1; if (tr[tr[v].ch[t ^ 1]].cnt - tr[tr[u].ch[t ^ 1]].cnt) return query(tr[u].ch[t ^ 1], tr[v].ch[t ^ 1], x, k - 1) + (1 << k); return query(tr[u].ch[t], tr[v].ch[t], x, k - 1); } int query(int l, int r, int x) { return query(root[l - 1], root[r], x, BITS - 1); } int tree_query(int x, int z) { return query(dfn[x], dfn[x] + siz[x] - 1, z); } int path_query(int x, int y, int z) { int ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); ans = max(ans, query(dfn[top[x]], dfn[x], z)); x = fa[top[x]]; } if (dep[x] < dep[y]) swap(x, y); ans = max(ans, query(dfn[y], dfn[x], z)); return ans; } int main() { cin >> n >> q; for (int i = 1; i <= n; i++) cin >> val[i]; for (int i = 1, u, v; i < n; i++) { cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dfs1(1, 0, 1); dfs2(1, 1); for (int i = 1; i <= n; i++) root[i] = insert(root[i - 1], val[rev[i]], BITS - 1); for (int opt, x, y, z; q–; ) { cin >> opt; if (opt == 1) { cin >> x >> z; cout << tree_query(x, z) << ‘\n’; } else { cin >> x >> y >> z; cout << path_query(x, y, z) << ‘\n’; } } return 0; }
07-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值