来源不明的题

给定一个长度为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\n",ans);
  }
  return 0;
}
posted @ 2019-07-04 18:01  comld  阅读(341)  评论(0编辑  收藏  举报