zoukankan      html  css  js  c++  java
  • 【HDU

    BUPT2017 wintertraining(15) #7C

    题意

    求[min((Z+L)%N,(Z+R)%N)+1,max((Z+L)%N,(Z+R)%N)+1]中不同前缀的个数,Z是上次询问的结果,N是字符串总个数。Q次询问。

    题解

    用主席树,即函数式线段树,维护前i个字符串的区间和(每个区间的前缀个数之和)。

    读入每个字符串后,用Trie树给它的每个前缀分配ID,并记录每个前缀最后出现的位置pre[cur],如果当前的前缀出现过,则线段树中上一次出现的位置的值-1,相当于只把这种前缀记录在最后出现的位置上。然后当前位置(第几个字符串)贡献了字符串长度个前缀。

    那么求[L,R]就相当于求前R个字符串对应的线段树的区间[L,n]的值,因为这样肯定不会包含只在R后面出现的前缀,而前R个字符串对应的线段树(主席树就相当于n个线段树),每个前缀只在最后出现的位置上有贡献,于是它[L,n]一定包含所有这个区间出现的前缀。

    代码

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <algorithm>
    
    const int N=100005;
    const int M=N*40;
    
    using namespace std;
    
    namespace PST{
        int T[N],lson[M],rson[M],tot,c[M],n;
    
        void init(int _n){
            tot=0;
            n=_n;
            memset(c,0,sizeof c);
        }
    
        int build(int l,int r){
            ++tot;
            c[tot]=0;
            if(l<r){
                int mid=l+r>>1;
                lson[tot]=build(l,mid);
                rson[tot]=build(mid+1,r);
            }
            return tot;
        }
    
        int update(int root,int pos,int val){
            int newroot=++tot, tmp=tot;
            c[tmp]=c[root]+val;
            int l=1,r=n;
    
            while(l<r){
                int mid=l+r>>1;
                if(pos<=mid){
                    lson[newroot]=++tot; rson[newroot]=rson[root];
                    root=lson[root];
                    r=mid;
                }
                else{
                    rson[newroot]=++tot; lson[newroot]=lson[root];
                    root=rson[root];
                    l=mid+1;
                }
    
                newroot = tot;
                c[newroot] = c[root] + val;
            }
            return tmp;
        }
    
        int query(int root,int pos){
            int ret=0;
            int l=1,r=n;
            while(l<pos){
                int mid=l+r>>1;
                if(pos<=mid){
                    ret+=c[rson[root]];
                    r=mid;
                    root=lson[root];
                }
                else{
                    l=mid+1;
                    root=rson[root];
                }
            }
            return c[root]+ret;
        }
    }
    
    namespace Trie{
        int node[N][27];
        int tot, pre[N];
    
        void Insert(string& s,int x){
            int cur=0;
            for(int i=0;i<s.size();++i){
                int p=s[i]-'a';
                if(node[cur][p]==0)
                    node[cur][p]=++tot;
    
                cur=node[cur][p];
                if(pre[cur]){
                    PST::T[x]=PST::update(PST::T[x], pre[cur], -1);
                }
                pre[cur]=x+1;
    
            }
        }
    
        void init(){
            tot=0;
            memset(node,0,sizeof node);
            memset(pre,0,sizeof pre);
        }
    }
    
    string s;
    
    int main(){
        int n;
        while(~scanf("%d",&n)){
            int z=0;
            Trie::init();
            PST::init(n);
            PST::T[0]=PST::build(1,n);
            for(int i=0;i<n;++i){
                if(i)PST::T[i]=PST::T[i-1];
                cin>>s;
                Trie::Insert(s, i);
                PST::T[i]=PST::update(PST::T[i], i+1, s.size());
            }
            int q;
            scanf("%d",&q);
            while(q--){
                int l,r;
                scanf("%d%d",&l,&r);
                l=(l+z)%n,r=(r+z)%n;
                if(r<l)swap(l,r);
                z=PST::query(PST::T[r],l+1);
                printf("%d
    ",z);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    原子核壳模型程序 BigStick 的用法
    c++ 中的下三角阵矩阵元标记
    BCS方程和Bogoliubov变换
    圆膜振动问题
    核结构单体跃迁算符
    python画球谐函数
    gnuplot 绘制球谐函数图
    shell 脚本小知识集锦
    6.12学习总结
    PHP网上商城
  • 原文地址:https://www.cnblogs.com/flipped/p/7091886.html
Copyright © 2011-2022 走看看