HDU-5790 Tire树+主席树

Prefix

Time Limit: 2000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 474    Accepted Submission(s): 150


Problem Description
Alice gets N strings. Now she has Q questions to ask you. For each question, she wanna know how many different prefix strings between Lth and Rth strings. It's so easy right? So solve it!
 

Input
The input contains multiple test cases.

For each test case, the first line contains one integer  N(1N100000) . Then next N lines contain N strings and the total length of N strings is between 1 and 100000. The next line contains one integer  Q(1Q100000) . We define a specail integer Z=0. For each query, you get two integer L, R(0=<L,R<N). Then the query interval [L,R] is [min((Z+L)%N,(Z+R)%N)+1,max((Z+L)%N,(Z+R)%N)+1]. And Z change to the answer of this query.
 

Output
For each question, output the answer.
 

Sample Input
  
  
3 abc aba baa 3 0 2 0 1 1 1
 

Sample Output
  
  
7 6 3
 

Author
ZSTU
 

Source

题目链接:

题目大意:
给出n个字符串,每次询问第L个字符串到第R个字符串中不同前缀的个数,强制在线。

解题思路:
之间有做过用Trie树哈希的题目,这个题其实就是用Trie给每个前缀一个值,这样就将一个字符串转化成了几个不同的数,再查询区间内不同数的个数就可以了,区间内不同数的个数用主席树来做。
比赛时用java写数组开到4e6就MLE了,赛后改了好几天过不了,只好向C++妥协。

AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = (int)4e6+10;
const int M = (int)1e5+10;

char s[M];
int n,sz,ct,pp,ans,m,a,b,L,R;
int aa[M],mm[M],last[M],lpos[M],rpos[M];
int rt[M],ll[N],rr[N],data[N],ch[M][26];

void insert()
{
    int u=0,a,len=strlen(s);
    for(int i=0;i<len;i++)
    {
        a=s[i]-'a';
        if(ch[u][a]==0)
        {
            ch[u][a]=++sz;
            for(int j=0;j<26;j++)
                ch[sz][j]=0;
        }
        u=ch[u][a];
        aa[++ct]=u;
    }
}
void build(int l,int r,int k)
{
    data[k]=0;
    if(l==r) return;
    int mid=(l+r)/2;
    ll[k]=++pp;build(l,mid,ll[k]);
    rr[k]=++pp;build(mid+1,r,rr[k]);
}
void updata(int a,int b,int k,int l,int r,int x)
{
    data[a]=data[b]+x;
    if(l==r) return;
    int mid=(l+r)/2;
    if(k<=mid)
    {
        rr[a]=rr[b];ll[a]=++pp;
        updata(ll[a],ll[b],k,l,mid,x);
    }
    else
    {
        ll[a]=ll[b];rr[a]=++pp;
        updata(rr[a],rr[b],k,mid+1,r,x);
    }
}
int query(int a,int b,int k,int l,int r)
{
    if(a<=l&&r<=b) return data[k];
    int mid=(l+r)/2,res=0;
    if(mid>=a) res+=query(a,b,ll[k],l,mid);
    if(mid+1<=b) res+=query(a,b,rr[k],mid+1,r);
    return res;
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=0;i<26;i++)
            ch[0][i]=0;
        sz=ct=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            lpos[i]=ct+1;
            insert();
            rpos[i]=ct;
        }
        for(int i=1;i<=sz;i++) mm[i]=N;
        for(int i=ct;i>0;i--)
        {
            last[i]=mm[aa[i]];
            mm[aa[i]]=i;
        }
        pp=0;
        rt[ct+1]=++pp;build(1,ct,rt[ct+1]);
        for(int i=ct;i>0;i--)
        {
            rt[i]=++pp;
            updata(rt[i],rt[i+1],i,1,ct,1);
            if(last[i]<N)
            {
                a=++pp;
                updata(a,rt[i],last[i],1,ct,-1);
                rt[i]=a;
            }
        }
        scanf("%d",&m);ans=0;
        while(m--)
        {
            scanf("%d%d",&a,&b);
            L=min((a+ans)%n,(b+ans)%n)+1;
            R=max((a+ans)%n,(b+ans)%n)+1;
            ans=query(lpos[L],rpos[R],rt[lpos[L]],1,ct);
            printf("%d\n",ans);
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值