题意:对于一个字符串(S),对于某个子串(S[l,r]),如(S[l,r]=S[1,r-l+1]),那么就称该子串为好的;给定序列(w_i),定义一个子串(S[l,r])的权值为(min_{i=l}^r w_i);
初始时有一空串,每次在该串末位加入一个字符(c_i),求每次操作后字符串所有好的子串的权值和;强制在线。
(nleq 6 imes 10^5,w_i<2^{30})
不难发现这个好的子串其实就是( m border),这个动态加入我们只需要考虑答案的增量即可。
考虑从(i-1)加一个字符(c_i)之后( m border)的变化,如果(x)在(S[1,i-1])是一个( m border),那么如果(S_{x+1}=c_i),那么(x+1)就是(S[1,i])的( m border),反之则不是;特殊地,当(S_1=c_i)时,(1)会成为一个( m border)。
我们发现这个变化比较简单,于是我们只需要考虑( m border)集合的变化即可。
加入新的( m border)特判一下即可;考虑如何删掉加入(c_i)后不合法的( m border),注意到(x)不合法当且仅当(S_{x+1} eq c_i),于是我们记(x)的颜色为(S_{x+1}),我们利用kmp构建一棵fali树,对于每一种颜色分别维护每个节点往上第一个该颜色的祖先;这样我们枚举(x)的颜色,从(i-1)暴力跳着删除即可;删除的时候贡献是一个区间( m min),对(w_i)动态构建一个st表即可;由于每个点只会被删除一次,所以复杂度是正确的。
之后对于合法的( m border),其只新增了一个(w_i),也就是贡献需要对(w_i)取一个(min),于是我们需要一个数据结构支持整体求和、将所有数和(w_i)取(min)、插入以及删除,刚上来写了个权值线段树发现被卡空间了,真实自闭;其实只需要一个std::map暴力修改即可,由于一次插入的数之后被暴力取(min)一次,复杂度也是均摊正确的。
之后答案可能是(n^2 imes w_i)级别,于是可能会爆long long,所以统计答案的时候需要一个高精。
代码
#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=600001;const LL B=(1<<30)-1;
char c[5],S[maxn];
int A[105],C[105],ans26,ansB,ln;
int n,w[maxn],mn[20][maxn],nxt[maxn],fa[26][maxn],lm;
short col[maxn],lg[maxn];
inline void add(LL x) {
ans26=(ans26+(x%26ll))%26;ansB=(ansB+(x&B))&B;
ln=0;while(x)C[++ln]=x%10,x/=10ll;lm=max(lm,ln);
for(re int i=1;i<=lm;i++)A[i]+=C[i],C[i]=0;
for(re int i=1;i<=lm;i++)A[i+1]+=A[i]/10,A[i]%=10;
while(A[lm+1]) A[lm+1]+=A[lm]/10,A[lm]%=10;++lm;
}
inline void write() {
for(re int i=lm;i;--i)putchar(A[i]+'0');puts("");
}
inline int ask(int l,int r) {
int k=lg[r-l+1];
return min(mn[k][r],mn[k][l+(1<<k)-1]);
}
inline void add_St(int pos) {
mn[0][pos]=w[pos];
for(re int i=1;(1<<i)<=pos;i++)
mn[i][pos]=min(mn[i-1][pos],mn[i-1][pos-(1<<(i-1))]);
}
struct Data_Structure {
typedef std::pair<int,int> pii;
long long tot;std::map<int,int>ma;int st[maxn],top;
std::map<int,int>::iterator it;
inline void ins(int x,int v) {ma[x]+=v;tot+=1ll*x*v;}
inline int qry(int x) {
int sz=0;it=ma.upper_bound(x);
for(;it!=ma.end();++it) {
pii nw=*it;st[++top]=nw.first;
tot-=1ll*nw.first*nw.second;sz+=nw.second;
}
while(top)ma.erase(st[top--]);return sz;
}
}seg;
inline void jump(int co,int x,int pos) {
while(x)seg.ins(ask(pos-x+1,pos),-1),x=fa[co][x];
}
int main() {
n=read();lm=1;for(re int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
for(re int l=1;l<=n;l++) {
scanf("%s",c);w[l]=read();
c[0]=(c[0]-'a'+(int)(ans26%26))%26+'a';w[l]^=(ansB&B);
add_St(l);S[l]=c[0];add(ask(1,l));
if(l==1) {write();continue;}
int p=nxt[l-1];
while(p&&S[p+1]!=S[l])p=nxt[p];
if(S[p+1]==S[l])nxt[l]=p+1;
col[l-1]=c[0]-'a';
for(re int i=0;i<26;++i)fa[i][l]=fa[i][nxt[l]];
fa[col[nxt[l]]][l]=nxt[l];
if(S[l]==S[1]) seg.ins(w[l],1);
for(re int i=0;i<26;++i) {
if(c[0]-'a'==i)continue;
jump(i,fa[i][l-1],l-1);
}
seg.ins(w[l],seg.qry(w[l]));
add(seg.tot);write();
}
return 0;
}