nflsoj 20034 #10301.「2020联考北附1」红蔷薇白玫瑰

在一棵无限延伸的二叉树上,缠绕着一株蔷薇花,它上面一共开了 \(n\) 朵蔷薇,构成了一个包含根节点的连通块。咒语是一个长为 \(m\) 的 \(01\) 串,若对一朵蔷薇念动咒语,则会有魔术回路沿着咒语向下传达。魔术回路会逐个按照咒语的每一个字符,若为 \(0\) 则传达到左子,若为 \(1\) 则传达到右子,如不存在则魔术失败。对于每朵蔷薇,问若对其念动咒语,魔术是否会失败,如成功则传达到哪朵玫瑰?

\(1\leq n,m\leq 3\cdot 10^5\)

一开始以为是一个数据结构,考虑根号分段,将 \(m\) 分成 \(\sqrt m\) 段,记录每个节点从指令 \(\sqrt m\) 个段开始走 \(\sqrt m\) 步能走到的节点 . 但是,发现我无法 \(\mathrm O(n\sqrt n)\) 的时间求出,弃掉了.

接着,我发现如果节点往下走 \(m\) 个,有多种选择,但是如果是节点往上走 \(m\) 个,只会有 \(1\) 种选择 .

如果 \(x\) 向上走 \(m\) 步的情况和给定 \(01\) 串相同,那么,向上走到的那个节点 \(y\) 向下走 \(m\) 步之后走到的节点就是 \(x\) .

考虑对每个节点向上走 \(\sqrt m\) 步的指令在指令 \(\sqrt m\) 个段中的位置 .

不用一一比对,可以算出一个哈希值,然后跟 \(\sqrt m\) 段的哈希值比对,这样,\(\mathrm O(n\sqrt m)\) 地求出 .

这样,往上跳 \(\sqrt m\) 就可以找到上面的节点 .

但是,受人提醒,发现还可以再优化 .

抛弃这题是一个数据结构的局限性,考虑求出节点 \(x\) 向上 \(m\) 步的哈希值,如果与指令的哈希值相等,那么,向上 \(m\) 步所到达的位置 \(y\) 线下走 \(m\) 步得到的就是 \(x\) .

现在要解决的问题就是如何求出每个节点上面 \(m\) 级的祖先 .

因为 \(m\) 固定,考虑在 dfs 的同时维护一个双端队列,保存路径,如果向下走的步数超过 \(m\) 层了,则弹出栈顶的元素,如果为 \(0\) ,则向左儿子走一步,否则,向右儿子走一步 .

那么,上面 \(m\) 个祖先的操作序列的哈希值也是一样,要维护一个双端队列,保存路径 . 超过 \(m\) 层的时候,弹出栈顶的元素,如果为 \(1\) ,就要哈希值就要减掉对应位的值 .

这两个 dfs 一定要记得回溯 .

时间复杂度 : \(O(n)\)

空间复杂度 : \(O(n)\)

code

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	int res=0;
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return res;
}
inline void print(int res){
	if(res==0){
		putchar('0');
		return;
	}
	int a[10],len=0;
	while(res>0){
		a[len++]=res%10;
		res/=10;
	}
	for(int i=len-1;i>=0;i--)
		putchar(a[i]+'0');
}
int n,m;
int a[300010];
int fa[300010],son[300010][2];
int dep[300010];
int anc[300010];
int Anc=0;
deque<int>q;
void get_anc(int x){
	if(son[x][0]!=-1){
		q.push_back(0);
		dep[son[x][0]]=dep[x]+1;
		int tmp,t;
		if(dep[son[x][0]]==m)
			anc[son[x][0]]=Anc;
		if(dep[son[x][0]]>m){
			tmp=Anc,t=q.front();
			Anc=son[Anc][t];
			anc[son[x][0]]=Anc;
			q.pop_front();
		}
		get_anc(son[x][0]);
		if(dep[son[x][0]]>m){
			Anc=tmp;
			q.push_front(t);
		}
		q.pop_back();
	}
	if(son[x][1]!=-1){
		q.push_back(1);
		dep[son[x][1]]=dep[x]+1;
		int tmp,t;
		if(dep[son[x][1]]==m)
			anc[son[x][1]]=Anc;
		if(dep[son[x][1]]>m){
			tmp=Anc,t=q.front();
			Anc=son[Anc][t];
			anc[son[x][1]]=Anc;
			q.pop_front();
		}
		get_anc(son[x][1]);
		if(dep[son[x][1]]>m){
			Anc=tmp;
			q.push_front(t);
		}
		q.pop_back();
	}
}
class Hash{
public:
	int mod,p[300010];
	int val,tar;
	void get_p(){
		p[0]=1;
		for(int i=1;i<300010;i++){
			p[i]=p[i-1]*2%mod;
		}
	}
}H[3];
int ans[300010];
void dfs(int x){
	if(dep[x]>=m){
		if(H[0].tar==H[0].val&&H[1].tar==H[1].val&&H[2].val==H[2].tar){
			ans[anc[x]]=x;
		}
	}
	if(son[x][0]!=-1){
		q.push_back(0);
		int tmp[3];
		for(int i=0;i<3;i++){
			tmp[i]=H[i].val;
			H[i].val=(H[i].val<<1)%H[i].mod;
			if(dep[son[x][0]]>m){
				H[i].val=(H[i].val-H[i].p[m]*q.front()+H[i].mod)%H[i].mod;
			}
		}
		int t;
		if(dep[son[x][0]]>m){
			t=q.front();
			q.pop_front();
		}
		dfs(son[x][0]);
		if(dep[son[x][0]]>m){
			q.push_front(t);
		}
		
		for(int i=0;i<3;i++)H[i].val=tmp[i];
		q.pop_back();	
	}
	if(son[x][1]!=-1){
		q.push_back(1);
		int tmp[3];
		for(int i=0;i<3;i++){
			tmp[i]=H[i].val;
			H[i].val=((H[i].val<<1)%H[i].mod+1)%H[i].mod;
			if(dep[son[x][1]]>m){
				H[i].val=(H[i].val-H[i].p[m]*q.front()+H[i].mod)%H[i].mod;
			}
		}
		int t;
		if(dep[son[x][1]]>m){
			t=q.front();
			q.pop_front();
		}
		dfs(son[x][1]);
		if(dep[son[x][1]]>m){
			q.push_front(t);
		}
		for(int i=0;i<3;i++)H[i].val=tmp[i];
		q.pop_back();
	}
}
int main(){
	freopen("rose.in","r",stdin);
	freopen("rose.out","w",stdout);
	n=read();
	memset(fa,-1,sizeof(fa));
	memset(son,-1,sizeof(son));
	fa[0]=-1;
	for(int i=0;i<n-1;i++){
		int u=read()-1,v=read()-1,type=read();
		son[u][type]=v;
	}
	m=read();
	for(int i=0;i<m;i++)a[i]=read();
	memset(anc,-1,sizeof(anc));
	get_anc(0);
	H[0].mod=998244353;H[1].mod=1000000007;H[2].mod=1000000009;
	for(int i=0;i<3;i++){
		H[i].get_p();
		H[i].val=H[i].tar=0;
	}	
	for(int i=0;i<3;i++)for(int j=0;j<m;j++){
		H[i].tar=((H[i].tar<<1)%H[i].mod+a[j])%H[i].mod;
	}
	while(!q.empty())q.pop_back();
	memset(ans,-1,sizeof(ans));
	dfs(0);
	for(int i=0;i<n;i++){
		print(ans[i]+1);
		putchar(' ');
	}
	putchar('\n');
	return 0;
}
/*inline? ll or int? size? min max?*/
上一篇:nflsoj 20034 #10231「2019五校联考-镇海3」小 ω 的图


下一篇:nflsoj 20034 #12442「NOIP2021模拟赛0923北大附」关键词