列表

详情


NC233446. 字典树简单题

描述

有一棵 n 个节点的 01 Trie。这棵 01 Trie 的根节点是 1,保证每一个叶子节点的深度都相同。
众所周知在 01 Trie 上可以快速的查询第 k 小的元素。但是这样太简单了,于是稍微加强了一下,需要支持以下两种操作:
如果你不了解 01 Trie,可以在 OI wiki 了解它的相关定义:https://oi-wiki.org/string/trie/#_6

输入描述

本题强制在线。每次操作中的 x 都需要异或上一次的答案 lastans。初始时 
第一行三个正整数 ,表示这棵 01 Trie 的初始节点数量,操作次数,以及 01 Trie 的深度(根节点 1 的深度为 1)。
第二至第 n 行,第 i 行有两个整数 ,表示点 i 01 Trie 上的父亲节点为 x,这条边的边权为 y
接下来 m 行,每行表示一次修改操作或一次询问操作。具体输入格式如题目描述所述。
保证修改操作加入的节点数量不超过 ;01 Trie 上所有点的父亲编号小于自己的编号;根节点到任意节点的路径上二进制数不同;询问操作的 k 不大于目前叶子节点的数量;所有操作中通过计算得到真实的 x 一定在 01 Trie 上。

输出描述

如果有 t 个询问操作,那么应该输出 t 行,其中第 i 行表示第 i 次询问的答案。

示例1

输入:

7 3 4
1 0
2 0
3 0
2 1
5 1
5 0
2 3 2
1 6 110
2 4 4

输出:

7
10

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 350ms, 内存消耗: 21548K, 提交时间: 2022-05-18 09:44:29

#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x; i<=y; ++i)
#define repd(i,x,y) for(int i=x; i>=y; --i)

using namespace std;
const int N=600005;
bool vis[N];
int n,m,len,fa[N],id[N],Fa[N],son[N][2],Son[N][2],ans,siz[N];
char s[N];

int getint()
{
	char ch;
	while(!isdigit(ch=getchar()));
	int x=ch-48;
	while(isdigit(ch=getchar())) x=x*10+ch-48;
	return x;
}

void getup(int x)
{
	if(x==1) return;
	int rt=fa[x],lst=x;
	id[x]=x;
	while(!vis[rt]) id[rt]=x,lst=rt,rt=fa[rt];
	Fa[x]=rt;
	if(son[rt][0]==lst) Son[rt][0]=x;
	else Son[rt][1]=x;
}

void getdown(int x)
{
	if(x==1) return;
	int rt=id[x];
	Fa[rt]=x;
	Son[x][(s[1]-'0')^1]=rt;
	vis[x]=1,siz[x]=siz[rt];
}

int dfs(int x,int k)
{
	if(!Son[x][0] && !Son[x][1]) return x;
	if(siz[Son[x][0]]>=k) return dfs(Son[x][0],k);
	return dfs(Son[x][1],k-siz[Son[x][0]]);
}

int main()
{
	n=getint(),m=getint(),getint();
	rep(i,2,n)
	{
		fa[i]=getint();
		son[fa[i]][getint()]=i;
	}
	rep(i,1,n)
	{
		vis[i]=(i==1 || (son[i][0] && son[i][1]) || (!son[i][0] && !son[i][1]));
		if(vis[i] && i>1)
		{
			int lst,x;
			id[i]=i;
			for(lst=i,x=fa[i]; !vis[x]; id[x]=i,lst=x,x=fa[x]);
			Fa[i]=x;
			if(son[x][0]==lst) Son[x][0]=i;
			else Son[x][1]=i;
		}
	}
	id[1]=1;
	repd(i,n,2)
	{
		if(!son[i][0] && !son[i][1]) siz[i]=1;
		if(vis[i]) siz[Fa[i]]+=siz[i];
	}
	while(m--)
	{
		int tp=getint(),x=getint()^ans;
		if(tp==1)
		{
			scanf("%s",s+1),len=strlen(s+1);
			getdown(x),getup(x);
			int lst=n+len;
			for(int y=x,i=1; i<=len; fa[++n]=y,son[y][s[i]-'0']=n,y=n,id[y]=lst,++i);
			vis[n]=1,Fa[n]=x,Son[x][s[1]-'0']=n;
			for(int y=n; y; y=Fa[y]) ++siz[y];
		}
		else
		{
			int k=getint();
			x=id[x];
			int y=x,lst=0;
			while(siz[y]<k) lst=y,y=Fa[y];
			if(y!=x)
			{
				if(Son[y][0]==lst) y=Son[y][1];
				else y=Son[y][0];
				k-=siz[lst];
			}
			printf("%d\n",ans=dfs(y,k));
		}
	}
	return 0;
}

上一题