联考20200801 T2 皮卡丘




分析:
整体思路是,没有被走到的点我们直接数学计算,走到的点暴力维护
考虑对每次探索操作维护二叉树,由于每个点在没有被删的情况下为自然生长,其出现时间就是它的深度,而被炸掉的点会在目前时间的下一刻长出来
我们在被炸掉的点上打上时间标记,表示这个点多久后才会长出来
每次向下探索时,维护路径上的时间差(这个点长出来的时间减去这个点本应长出来的时间),用于统计子树内因删除而没有长出来的节点
维护全局变量(Sz)(Lf)表示总节点数和叶子个数,生长时通过数学计算更新,删除时在建出来的二叉树上寻找删除的大小来更新
总时间复杂度为(O(n+sum|S|))

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

#define maxn 1000005
#define MOD 998244353
#define inv2 499122177

using namespace std;

inline long long getint()
{
	long long num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,Tim;
int pw[maxn];
int ch[maxn][2],tim[maxn],tot;
int Lf,Sz,wp,wl,L;
char op[maxn];

inline void update(int &u,int p,int ldt)
{
	if(!u)
	{
		if(Tim-ldt-p+1>=0)wp=(wp+pw[Tim-ldt-p+1]-1)%MOD;
		if(Tim-ldt-p>=0)wl=(wl+pw[Tim-ldt-p])%MOD;
		return;
	}
	if(Tim-ldt-p>0)wp++;
	if(tim[u]!=-1)ldt=max(ldt,tim[u]-p);
	update(ch[u][0],p+1,ldt),update(ch[u][1],p+1,ldt);
	u=0;
}

inline void dfs(int u,int p,int ldt)
{
	if(tim[u]!=-1)ldt=max(ldt,tim[u]-p);
	if(p==L)
	{
		wp=wl=0;
		if(Tim-ldt-p<=0)wl=1;
		update(ch[u][0],p+1,ldt),update(ch[u][1],p+1,ldt);
		Sz=(Sz-wp-1)%MOD;
		Lf=(Lf-wl+inv2)%MOD;
		tim[u]=Tim+1;
		return;
	}
	int d=(op[p]=='R');
	if(!ch[u][d])ch[u][d]=++tot,tim[ch[u][d]]=-1,ch[tot][0]=ch[tot][1]=0;
	dfs(ch[u][d],p+1,ldt);
}

int main()
{
	freopen("pikachu.in","r",stdin);
	freopen("pikachu.out","w",stdout);

	int T=getint();
	pw[0]=1;
	for(int i=1;i<maxn;i++)pw[i]=2*pw[i-1]%MOD;
	memset(tim,-1,sizeof tim);
	while(T--)
	{
		n=getint();
		Lf=Sz=1,tot=Tim=0;
		ch[0][0]=ch[0][1]=0;
		while(n--)
		{
			scanf("%s",op);
			if(op[0]=='G')
			{
				int x=getint();
				Tim+=x;
				Sz=(Sz+1ll*Lf*(pw[x+1]-2))%MOD;
				Lf=1ll*Lf*pw[x]%MOD;
			}
			else scanf("%s",op),L=strlen(op),dfs(0,0,0);
			printf("%d
",(Sz+MOD)%MOD);
		}
	}
}

原文地址:https://www.cnblogs.com/Darknesses/p/13422987.html