前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【HDU - 5790 】Prefix(主席树+Trie树)

【HDU - 5790 】Prefix(主席树+Trie树)

作者头像
饶文津
发布2020-06-02 14:59:50
2540
发布2020-06-02 14:59:50
举报

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\n",z);
        }
    }
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-06-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题意
  • 题解
  • 代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档