您的位置:首页 > 其它

Codeforces Round #305 (Div. 1)E. Mike and Friends 后缀数组+RMQ+线段树

2015-05-29 14:29 597 查看
E. Mike and Friends

time limit per test
3 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

What-The-Fatherland is a strange country! All phone numbers there are strings consisting of lowercase English letters. What is double strange that a phone number can be associated with several bears!

In that country there is a rock band called CF consisting of
n bears (including Mike) numbered from 1 to
n.



Phone number of i-th member of CF is
si. May 17th is a holiday named Phone Calls day. In the last Phone Calls day, everyone called all the numbers that are substrings of his/her number (one may call some number several times). In particular,
everyone called himself (that was really strange country).

Denote as call(i, j) the number of times that
i-th member of CF called the
j-th member of CF.

The geek Mike has q questions that he wants to ask you. In each question he gives you numbers
l, r and k and you should tell him the number



Input
The first line of input contains integers n and
q (1 ≤ n ≤ 2 × 105 and
1 ≤ q ≤ 5 × 105).

The next n lines contain the phone numbers,
i-th line contains a string
si consisting of lowercase English letters (

).

The next q lines contain the information about the questions, each of them contains integers
l, r and k (1 ≤ l ≤ r ≤ n and
1 ≤ k ≤ n).

Output
Print the answer for each question in a separate line.

Sample test(s)

Input
5 5
a
ab
abab
ababab
b
1 5 1
3 5 1
1 5 2
1 5 3
1 4 5


Output
7
5
6
3
6


参考自:/article/1972582.html

思路:将字符串拼接起来,求一次后缀数组,求后缀数组时保存每个字符属于哪个串,每个串的起始位置,然后我们以sa数组作为下标建立线段树,线段树每个节点代表的区间,保存这个区间内每个字符属于哪个串,然后排序

对于一个询问包含的串K,找到K的起点在sa上的位置,我们可以二分其在sa数组上能延伸的最左端点以及最右端点,使得这之间的所有串与K的lcp都大于等于K的串长。然后我们只要在线段树内统计编号大于等于i且小于等于j的数个数就好了,这个我们只要在每个被完全包含的区间内二分答案,然后累加即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=400100;
const int INF=1000000000;
int N,M;
int sa[maxn],height[maxn],Rank[maxn],t[maxn],t2[maxn],c[maxn];
int str[maxn];
int len[maxn],id[maxn];
int belong[maxn],st[maxn];
int n;
int d[maxn][20];
void build_sa(int m,int n)
{
    int *x=t,*y=t2;
    for(int i=0;i<m;i++)c[i]=0;
    for(int i=0;i<n;i++)c[x[i]=str[i]]++;
    for(int i=1;i<m;i++)c[i]+=c[i-1];
    for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(int k=1;k<=n;k<<=1)
    {
        int p=0;
        for(int i=n-k;i<n;i++)y[p++]=i;
        for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(int i=0;i<m;i++)c[i]=0;
        for(int i=0;i<n;i++)c[x[y[i]]]++;
        for(int i=1;i<m;i++)c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);p=1;
        x[sa[0]]=0;
        for(int i=1;i<n;i++)
            x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++);
        if(p>=n)break;
        m=p;
    }
}
void getheight(int n)
{
    int k=0;
    for(int i=1;i<=n;i++)Rank[sa[i]]=i;
    for(int i=0;i<n;i++)
    {
        if(k)k--;
        int j=sa[Rank[i]-1];
        while(str[j+k]==str[i+k])k++;
        height[Rank[i]]=k;
    }
}
void initRMQ(int n)
{
    memset(d,0,sizeof(d));
    for(int i=0;i<=n;i++)d[i][0]=height[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=0;i+(1<<j)<=n+1;i++)
        d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
int LCP(int x,int y)
{
    if(x>y)swap(x,y);
    int k=0;
    while((1<<(k+1))<=(y-x+1))k++;
    return min(d[x][k],d[y-(1<<k)+1][k]);
}

int getl(int l,int r,int len)
{
    int x=r;
    while(l<r)
    {
        int mid=(l+r)>>1;
        int tmp=LCP(mid+1,x);
        if(tmp>=len)r=mid;
        else l=mid+1;
    }
    return l;
}
int getr(int l,int r,int len)
{
    int x=l;
    while(l<r)
    {
        int mid=(r+l+1)>>1;
        int tmp=LCP(x+1,mid);
        if(tmp>=len)l=mid;
        else r=mid-1;
    }
    return r;
}
struct IntervalTree
{
    vector<int> id[maxn<<2];
    void build(int o,int l,int r)
    {
        id[o].clear();
        for(int i=l;i<=r;i++)
            id[o].push_back(belong[sa[i]]);
        id[o].push_back(INF);
        sort(id[o].begin(),id[o].end());
        if(l==r)return ;
        int mid=(l+r)>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
    }
    int query(int o,int l,int r,int q1,int q2,int x,int y)
    {
        if(q1<=l&&r<=q2)
        {
            int L=lower_bound(id[o].begin(),id[o].end(),x)-id[o].begin()-1;
            int R=lower_bound(id[o].begin(),id[o].end(),y+1)-id[o].begin()-1;
            return R-L;
        }
        int mid=(l+r)>>1;
        int ans=0;
        if(q1<=mid)ans+=query(o<<1,l,mid,q1,q2,x,y);
        if(q2>mid)ans+=query(o<<1|1,mid+1,r,q1,q2,x,y);
        return ans;
    }
}tree;
void solve()
{
    tree.build(1,1,n);
    while(M--)
    {
        int x,y,k;
        scanf("%d%d%d",&x,&y,&k);
        int l=getl(1,Rank[st[k]],len[k]);
        int r=getr(Rank[st[k]],n,len[k]);
        int ans=tree.query(1,1,n,l,r,x,y);
        printf("%d\n",ans);
    }
}
char s[maxn];
int main()
{
    scanf("%d%d",&N,&M);
    n=0;
    int n1=27;
    for(int i=1;i<=N;i++)
    {
        scanf("%s",s);
        len[i]=strlen(s);
        st[i]=n;
        for(int j=0;j<len[i];j++)
            belong
=i,str[n++]=s[j]-'a'+1;
        belong
=0;
        str[n++]=n1++;
    }
    str
=0;
    build_sa(n1,n+1);
    getheight(n);
    initRMQ(n);
    solve();
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: