ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-10-02 16:34:36  阅读:227  来源: 互联网

标签:北附 nflsoj Anc int sqrt son dep front 联考


在一棵无限延伸的二叉树上,缠绕着一株蔷薇花,它上面一共开了 \(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,Anc,int,sqrt,son,dep,front,联考
来源: https://www.cnblogs.com/suadwm/p/15362106.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有