每次加一个串 x 会增加 n-max{LCP(x,i)},因为是树上,max{LCP(x,i)}就肯定是dfs序中跟它相邻的点,也就是它们的lca深度最深。
那么就用set维护一下dfs序,比较的话,用主席树维护hash
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <string>
#define fi first
#define se second
using namespace std;
typedef unsigned long long ll;
typedef pair<ll,ll> pari;
const int N=100010,P1=1e9+7,P2=1e9+9;
const pari base={7,29};
int n,q,t,cnt,g,rt[N*50],ls[N*50],rs[N*50],tag[N*50],tot[N*50];
pari pw[N],v[N*50],p[N];
pari operator +(const pari &a,const pari &b){ return pari((a.fi+b.fi)%P1,(a.se+b.se)%P2); }
pari operator -(const pari &a,const pari &b){ return pari((a.fi+P1-b.fi)%P1,(a.se+P2-b.se)%P2); }
pari operator *(const pari &a,const pari &b){ return pari((a.fi*b.fi)%P1,(a.se*b.se)%P2); }
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline void set1(int &g,int l,int r){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; tag[g]=tag[k]; tot[g]=tot[k]; v[g]=v[k];
tot[g]=r-l+1; v[g]=p[r-l]; tag[g]=1;
}
inline void set0(int &g,int l,int r){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; tag[g]=tag[k]; tot[g]=tot[k]; v[g]=v[k];
tot[g]=0; v[g]={0,0}; tag[g]=0;
}
inline void Push(int &g,int L,int R){
if(~tag[g]){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; tag[g]=tag[k]; tot[g]=tot[k]; v[g]=v[k];
int mid=L+R>>1;
if(tag[g])
set1(ls[g],L,mid),set1(rs[g],mid+1,R);
else
set0(ls[g],L,mid),set0(rs[g],mid+1,R);
tag[g]=-1;
}
}
inline bool cmp(int &a,int &b,int l,int r){
Push(a,l,r); Push(b,l,r);
if(l==r) return v[a]<v[b];;
int mid=l+r>>1;
if(v[ls[a]]==v[ls[b]])
return cmp(rs[a],rs[b],mid+1,r);
else
return cmp(ls[a],ls[b],l,mid);
}
struct u{
int x;
friend bool operator ==(u a,u b){
return v[a.x]==v[b.x];
}
friend bool operator <(u a,u b){
if(v[a.x]==v[b.x]) return false;
return cmp(a.x,b.x,1,n);
}
};
set<u> S;
long long ans;
int Find(int &g,int l,int r,int L,int R){
if(!g) return r;
if(L==R) return tot[g]?-1:L;
int mid=L+R>>1; Push(g,L,R);
if(l==L && r==R){
if(tot[rs[g]]!=R-mid) return Find(rs[g],mid+1,r,mid+1,R);
return Find(ls[g],l,mid,L,mid);
}
if(r<=mid) return Find(ls[g],l,r,L,mid);
else if(l>mid) return Find(rs[g],l,r,mid+1,R);
int ret=Find(rs[g],mid+1,r,mid+1,R);
if(~ret) return ret;
return Find(ls[g],l,mid,L,mid);
}
inline void Up(int g,int l){
v[g]=v[ls[g]]*pw[l]+v[rs[g]];
tot[g]=tot[ls[g]]+tot[rs[g]];
}
void Cover(int &g,int l,int r,int L,int R){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; tag[g]=tag[k]; tot[g]=tot[k]; v[g]=v[k];
if(l==L && r==R) return set0(g,L,R);
int mid=L+R>>1; Push(g,L,R);
if(r<=mid) Cover(ls[g],l,r,L,mid);
else if(l>mid) Cover(rs[g],l,r,mid+1,R);
else Cover(ls[g],l,mid,L,mid),Cover(rs[g],mid+1,r,mid+1,R);
Up(g,R-mid);
}
void Modify(int &g,int x,int L,int R){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; tag[g]=tag[k]; tot[g]=tot[k]; v[g]=v[k];
if(L==R) return set1(g,L,R);
int mid=L+R>>1; Push(g,L,R);
if(x<=mid) Modify(ls[g],x,L,mid);else Modify(rs[g],x,mid+1,R);
Up(g,R-mid);
}
inline int Same(int x,int y){
if(v[x]==v[y]) return n+1;
int l=1,r=n;
while(l<r){
int mid=l+r>>1;
if(v[ls[x]]==v[ls[y]])
Push(rs[x],mid+1,r),Push(rs[y],mid+1,r),x=rs[x],y=rs[y],l=mid+1;
else
Push(ls[x],l,mid),Push(ls[y],l,mid),x=ls[x],y=ls[y],r=mid;
}
return l;
}
int main(){
rea(t);
pw[0]=p[0]={1,1}; for(int i=1;i<=100000;i++) p[i]=p[i-1]+(pw[i]=pw[i-1]*base);
while(t--){
rea(n); rea(q); S.clear();
memset(tag,-1,sizeof(tag)); g=0; ans=0;
for(int i=1;i<=n;i++) rt[i]=0; cnt=0;
for(int i=1;i<=q;i++){
if(i==4)
int ssss=0;
char c; while((c=nc())!='?' && c!='!');
if(c=='?') printf("%lld\n",max(ans,1LL));
else{
int x; rea(x); x=n-x;
rt[g+1]=rt[g]; g++;
int pos=Find(rt[g],1,x,1,n);
if(~pos){
if(pos+1<=x) Cover(rt[g],pos+1,x,1,n);
Modify(rt[g],pos,1,n);
}
else Cover(rt[g],1,x,1,n);
Push(rt[g],1,n);
if(S.find(u{rt[g]})!=S.end()){
continue;
}
set<u>::iterator IT=S.insert(u{rt[g]}).first;
int cur=0; ans+=n+1;
if(IT!=S.begin())
IT--,cur=Same(IT->x,rt[g]),IT++;
IT++;
if(IT!=S.end())
cur=max(cur,Same(IT->x,rt[g]));
ans-=cur;
}
}
}
return 0;
}