CF710F String Set Queries
阿新 • • 發佈:2022-03-19
題面傳送門
完全顛覆了我對於二進位制分組的認知,本來以為那東西只能優化多重揹包還被單調佇列吊起來打來著。
首先這個題如果不強制線上可以發現就是個AC自動機sb題。
但是問題是它強制線上了,就有一些奇技淫巧來做。
首先顯然可以對詢問分塊,但是有一個26的常數的根號顯然跑不過去。
但是可以二進位制分組呀。
就是像一個2048一樣,每次在最後塞進去一個字串然後長度相同不斷合併,到最後只會剩下\(O(\log n)\)個AC自動機以及每個字串最多會被合併\(O(\log n)\)次。
然後就做到了\(O(\sum{|T|}\log n)\)
合併啥的寫個Trie合併就好了,雖然跑得有點慢。
code:
#include<bits/stdc++.h> #define I inline #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define abs(x) ((x)>0?(x):-(x)) #define re register #define RI re int #define ll long long #define db double #define lb long db #define N (300000+5) #define M (400000+5) #define mod 998244353 #define Mod (mod-1) #define eps (1e-9) #define U unsigned int #define it iterator #define Gc() getchar() #define Me(x,y) memset(x,y,sizeof(x)) #define Mc(x,y) memcpy(x,y,sizeof(x)) #define d(x,y) (n*(x-1)+(y)) #define R(n) (rand()*rand()%(n)+1) #define Pc(x) putchar(x) #define LB lower_bound #define UB upper_bound #define PB push_back using namespace std; int n,m,k,op,Hi,Hd,Io[20],Is[20],Do[20],Ds[20];char A[N];ll Ans; namespace AC{ int Len,Tp,x,FI[N],son[N][27],cnt,Val[N],F[N][27],S[N];queue<int> Q;I int Ins(char *s){x=Tp=++cnt;Len=strlen(s+1);for(RI i=1;i<=Len;i++) son[x][s[i]-'a']=++cnt,x=son[x][s[i]-'a'];Val[x]++;return Tp;} I void BFS(int x){RI i;S[x]=0;FI[x]=x;Mc(F[x],son[x]);for(i=0;i<26;i++) F[x][i]?(Q.push(F[x][i]),FI[F[x][i]]=x):(F[x][i]=x); while(!Q.empty()) for(x=Q.front(),Q.pop(),S[x]=S[FI[x]]+Val[x],Mc(F[x],son[x]),i=0;i<26;i++) F[x][i]?(Q.push(F[x][i]),FI[F[x][i]]=F[FI[x]][i]):(F[x][i]=F[FI[x]][i]);} I int ME(int x,int y){if(!x||!y) return x|y;Val[x]+=Val[y];for(RI i=0;i<26;i++) son[x][i]=ME(son[x][i],son[y][i]);return x;} I ll Qry(int x,char *A){ll Ans=0;Len=strlen(A+1);for(RI i=1;i<=Len;i++) x=F[x][A[i]-'a'],Ans+=S[x];return Ans;} } int main(){ freopen("1.in","r",stdin); RI i;scanf("%d",&n);while(n--){ scanf("%d%s",&op,A+1);if(op==1){Io[++Hi]=AC::Ins(A);AC::BFS(Io[Hi]);Is[Hi]=1;while(Is[Hi]==Is[Hi-1]) Hi--,Is[Hi]<<=1,AC::ME(Io[Hi],Io[Hi+1]),AC::BFS(Io[Hi]);} else if(op==2){Do[++Hd]=AC::Ins(A);AC::BFS(Do[Hd]);Ds[Hd]=1;while(Ds[Hd]==Ds[Hd-1]) Hd--,Ds[Hd]<<=1,AC::ME(Do[Hd],Do[Hd+1]),AC::BFS(Do[Hd]);} else {Ans=0;for(i=1;i<=Hi;i++) Ans+=AC::Qry(Io[i],A);for(i=1;i<=Hd;i++) Ans-=AC::Qry(Do[i],A);printf("%lld\n",Ans);fflush(stdout);} } }