联考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\n",(Sz+MOD)%MOD);
}
}
}