1. 程式人生 > 實用技巧 >聯考20200801 T2 皮卡丘

聯考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);
		}
	}
}