给定一个长度为n 的字符串s 和m 个单词,每个单词有权值。
定义一个串的价值为所有单词的价值与其出现次数的积之和。现
在有q 组询问,每次询问s 的一个区间的价值。强制在线,要求
poly(log)。
题解
有一个非常强的AC自动机做法,我不会。
考虑大力维护信息,我们在AC自动机上的每个点维护一下这个点代表的串的每一个后缀的价值。
维护的方法可以从fail指针和trie上的父亲继承。
用可持久化FHQ维护。
代码
不知道对不对(
#include<bits/stdc++.h>
#define ls l[cnt]
#define rs r[cnt]
#define P pair<int,int>
#define mm make_pair
#define N 500009
using namespace std;
typedef long long ll;
const int M=N*60;
queue<int>q;
char s[N];
int tot,op,m,n,len[N];
int fail[N],rt[N],ch[N][26],id[N],f[N];
int l[M],r[M],size[M];
ll sum[M],val[M],v[N];
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
inline int newnode(int ptr){
int cnt=++tot;
l[cnt]=l[ptr];r[cnt]=r[ptr];
sum[cnt]=sum[ptr];val[cnt]=val[ptr];
size[cnt]=size[ptr];
return cnt;
}
inline void pushup(int cnt){
size[cnt]=size[ls]+size[rs]+1;
sum[cnt]=sum[ls]+sum[rs]+val[cnt];
}
inline P split(int cnt,int k){
if(!cnt)return mm(0,0);
cnt=newnode(cnt);
if(k<=size[l[cnt]]){
P ans=split(l[cnt],k);
l[cnt]=ans.second;
pushup(ans.second=cnt);
return ans;
}
P ans=split(r[cnt],k-size[l[cnt]]-1);
rs=ans.first;
pushup(ans.first=cnt);
return ans;
}
int merge(int x,int y){
if(!x||!y)return newnode(x|y);
if(rand()%(size[x]+size[y])<size[x]){
x=newnode(x);
r[x]=merge(r[x],y);
pushup(x);
return x;
}
y=newnode(y);
l[y]=merge(x,l[y]);
pushup(y);
return y;
}
inline void get_fail(){
for(int i=0;i<26;++i)if(ch[0][i])q.push(ch[0][i]),len[ch[0][i]]=1;
while(!q.empty()){
int u=q.front();q.pop();
id[++id[0]]=u;
for(int i=0;i<26;++i){
if(ch[u][i]){
len[ch[u][i]]=len[u]+1;
fail[ch[u][i]]=ch[fail[u]][i];
q.push(ch[u][i]);
}
else ch[u][i]=ch[fail[u]][i];
}
}
}
int main(){
n=rd();m=rd();op=rd();
scanf("%s",s+1);
int pre=0;
for(int i=1;i<=n;++i){
ch[pre][s[i]-'a']=++tot;
f[tot]=pre;
pre=tot;
}
int x;
for(int i=1;i<=m;++i){
scanf("%s",s+1);
int len=strlen(s+1),now=0;
for(int j=1;j<=len;++j){
if(!ch[now][s[j]-'a']){
ch[now][s[j]-'a']=++tot;
f[tot]=now;
}
now=ch[now][s[j]-'a'];
}
scanf("%d",&x);
v[now]+=x;
}
get_fail();
tot=0;
for(int i=1;i<=id[0];++i){
int x=id[i];
if(fail[x])rt[x]=merge(split(rt[f[x]],len[x]-len[fail[x]]).first,rt[fail[x]]);
else size[++tot]=1,rt[x]=merge(rt[f[x]],tot);
if(v[x]){
P tmp=split(rt[x],1);
val[tmp.first]+=v[x];
pushup(tmp.first);
rt[x]=merge(tmp.first,tmp.second);
}
}
m=rd();
ll ans=0;
while(m--){
int l=rd(),r=rd();
l^=ans*op;r^=ans*op;
ans=sum[split(rt[r],l-1).second];
printf("%lld
",ans);
}
return 0;
}