• 来源不明的题


    给定一个长度为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;
    }
    
  • 相关阅读:
    Android给ListView设置分割线Divider样式
    Android监听ScrollView滑动到顶端和底部
    .Net——使用.net内置处理程序处理自己定义节点Demo
    Java---25---集合框架共性方法
    网络基础——知识生活化会变得如此简单
    Jquery节点遍历
    Rapha&#235;l 中文帮助文档(API)
    Fitnesse使用系列二
    UVa 10188
    Powershell Mail module, 发送outbox 里的全部邮件(一个.csv文件代表一封邮件)
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/11134030.html
Copyright © 2020-2023  润新知