聯考20200801 T2 皮卡丘
阿新 • • 發佈:2020-08-02
分析:
整體思路是,沒有被走到的點我們直接數學計算,走到的點暴力維護
考慮對每次探索操作維護二叉樹,由於每個點在沒有被刪的情況下為自然生長,其出現時間就是它的深度,而被炸掉的點會在目前時間的下一刻長出來
我們在被炸掉的點上打上時間標記,表示這個點多久後才會長出來
每次向下探索時,維護路徑上的時間差(這個點長出來的時間減去這個點本應長出來的時間),用於統計子樹內因刪除而沒有長出來的節點
維護全域性變數\(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); } } }