bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)

2754: [SCOI2012]喵星球上的点名

Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 2745 Solved: 1190
[Submit][Status][Discuss]

Description

a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?

Input

现在定义喵星球上的字符串给定方法:
先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数N和M。
接下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的字符串。
接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。

Output

对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。


把姓名串和询问串连在一起求\(SA\),以下为\(rk\)意义下;
然后对于每一个询问串二分求出\(LCP\)等于它长度的区间,及询问串出现位置;
这样的话第一问就是求每个区间内不同的数的个数,即\(HH\)的项链,莫队/树状数组;
第二问一个区间中属于同一个串的多个后缀会被重复计算,所以把相邻的重复后缀的贡献作差;
对于每个询问\([l,r]\),在\(l\)处将\(w\)区间加\(1\),\(r+1\)处区间减\(1\),则后缀\(i\)的贡献为\(w[i]-w[las[num[i]]]\);
\(las[num[i]]\)为上一个与\(i\)母串相同的后缀,树状数组即可;
AC GET☆DAZE

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define N 600039
#define mod 20070831
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
struct question
{
    int sd,l,r,ans;
}ask[N/6];
int neko,wa,fir[N/3],len[N/3],bel[N],bit[N],ans[N];
int n,m,num[N],SA[N],rk[N],Height[N],las[N],buc[N],pw[20],st[N][20];
bool cmp_hh(question i,question j) {return i.r<j.r;}
bool cmp_sd(question i,question j) {return i.sd<j.sd;}
void get_string(int stp)
{
    fir[stp]=n+1;
    scanf("%d",&len[stp]);
    for(int a=1;a<=len[stp];a++)
    {
        scanf("%d",&num[++n]);
        num[n]++,bel[n]=stp;
    }
    num[++n]=10001+stp;
}
bool judge(int i,int j,int k)
{
    return las[i]==las[j] && las[i+k]==las[j+k];
}
void radix_sort()
{
    for(int a=1;a<=m;a++) buc[a]=0;
    for(int a=1;a<=n;a++) buc[rk[las[a]]]++;
    for(int a=1;a<=m;a++) buc[a]+=buc[a-1];
    for(int a=n;a>=1;a--) SA[buc[rk[las[a]]]--]=las[a];
}
void get_SA()
{
    for(int a=1;a<=n;a++) rk[a]=num[a],las[a]=a;
    m=N-39,radix_sort();
    for(int a=1,b=0;m<n || a==1;a<<=1,b=0)
    {
        for(int c=n-a+1;c<=n;c++) las[++b]=c;
        for(int c=1;c<=n;c++) if(SA[c]>a) las[++b]=SA[c]-a;
        radix_sort(),m=0;
        for(int c=1;c<=n;c++) las[c]=rk[c];
        for(int c=1;c<=n;c++) rk[SA[c]]=(judge(SA[c-1],SA[c],a) ? m : ++m);
    }
    for(int a=1,b=0;a<=n;a++,b=max(0,b-1))
    {
        while(num[a+b]==num[SA[rk[a]-1]+b]) b++;
        Height[rk[a]]=b;
    }
}
void get_st()
{
    pw[0]=1;
    for(int a=1;pw[a-1]<=n;a++) pw[a]=pw[a-1]<<1;
    for(int a=1;a<=n;a++) st[a][0]=Height[a];
    for(int a=1;pw[a]<=n;a++)
    {
        for(int b=1;b<=n;b++)
        {
            st[b][a]=min(st[b][a-1],st[b+pw[a-1]][a-1]);
        }
    }
}
int RMQ(int l,int r)
{
    int stp=log((double)r-l+1)/log(2.0);
    return min(st[l][stp],st[r-pw[stp]+1][stp]);
}
int search_mae(int stp)
{
    int l=1,r=rk[fir[stp]]-1,mid,res=rk[fir[stp]];
    while(l<=r)
    {
        mid=l+r>>1;
        if(RMQ(mid+1,rk[fir[stp]])<len[stp]) l=mid+1;
        else r=mid-1,res=mid;
    }
    return res;
}
int search_ato(int stp)
{
    int l=rk[fir[stp]]+1,r=n,mid,res=rk[fir[stp]];
    while(l<=r)
    {
        mid=l+r>>1;
        if(RMQ(rk[fir[stp]]+1,mid)<len[stp]) r=mid-1;
        else l=mid+1,res=mid;
    }
    return res;
}
void update(int p,int v)
{
    if(!p) return;
    while(p<=n) bit[p]+=v,p+=(-p&p);
}
int query(int p)
{
    int res=0;
    while(p) res+=bit[p],p-=(-p&p);
    return res;
}
int main()
{
    scanf("%d%d",&neko,&wa);
    for(int a=1,b;a<=neko;a++)
    {
        get_string(2*a-1);
        get_string(2*a);
    }
    for(int a=1,b;a<=wa;a++)
    {
        get_string(2*neko+a);
    }
    get_SA(),get_st();
    for(int a=1;a<=wa;a++)
    {
        ask[a].sd=a;
        ask[a].l=search_mae(2*neko+a);
        ask[a].r=search_ato(2*neko+a);
    }
    sort(ask+1,ask+wa+1,cmp_hh);
    for(int a=0;a<=neko;a++) las[a]=0;
    for(int a=1,b=1;a<=wa;a++)
    {
        while(b<=ask[a].r)
        {
            if(bel[SA[b]]<=2*neko)
            {
                update(las[bel[SA[b]]+1>>1],-1);
                las[bel[SA[b]]+1>>1]=b;
                update(b,1);
            }
            b++;
        }
        ask[a].ans=query(ask[a].r)-query(ask[a].l-1);
    }
    for(int a=0;a<=neko;a++) las[a]=0;
    for(int a=1;a<=n;a++) bit[a]=0;
    for(int a=1;a<=wa;a++) update(ask[a].l,1);
    for(int a=1,b=1;a<=n;a++)
    {
        while(b<=wa && ask[b].r<a)
        {
            update(ask[b].l,-1);
            b++;
        }
        if(bel[SA[a]]<=2*neko)
        {
            ans[bel[SA[a]]+1>>1]+=query(a)-query(las[bel[SA[a]]+1>>1]);
            las[bel[SA[a]]+1>>1]=a;
        }
    }
    sort(ask+1,ask+wa+1,cmp_sd);
    for(int a=1;a<=wa;a++) printf("%d\n",ask[a].ans);
    for(int a=1;a<=neko;a++)
    {
        printf("%d",ans[a]);
        if(a<neko) printf(" ");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Sinogi/p/8689076.html

时间: 2024-09-29 10:27:26

bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)的相关文章

BZOJ 2754([SCOI2012]喵星球上的点名-后缀数组统计序列集合中子序列出现次数)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 805  Solved: 380 [Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,

BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

[BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组

a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到. 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示.为了方便描述,a180285决定用数串来表示喵星人的名字. 现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?

BZOJ2754 SCOI2012喵星球上的点名

绝世好题. 正当我犹豫不决时,hzwer说:“MAP!!!” 没错这题大大的暴力,生猛的stl,贼基尔爽,,???,, 由于我们求点名在名字中的子串个数,所以将点名建AC自动机,记录节点属于哪次点名,每次带着这位同学的所有名字去里面扫,注意判重 复杂度20000*100000以及玄学的stl复杂度. By:大奕哥 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+10; 4 int ans1[N],ans2[N

bzoj2754 [SCOI2012]喵星球上的点名

题目链接 AC自动机 由于输入的是恶心的数字,用了map强行带log…… 由于不清楚长度,用了vector强行增加时间…… 由于要判重,用了数组存下强行加常数…… 慢惨了 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<string> 7 #include&l

bzoj 2754 [SCOI2012]喵星球上的点名(后缀数组)

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1359  Solved: 618[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那

P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队)

P2336 [SCOI2012]喵星球上的点名 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> #define rint register int using namespace std; int read(){ char c=getchar();int x=0; while(

BZOJ 2754: [SCOI2012]喵星球上的点名

2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1926  Solved: 850[Submit][Status][Discuss] Description a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这

[SCOI2012]喵星球上的点名——堪称九种方法做的题

题意: 给你N个串对,M个询问串,对每个询问串求是多少串对的子串(在串对的某一个中作为子串),以及每个串对最终是包含了多少询问串 方法众多.. 可谓字符串家族八仙过海各显神通. 复杂度不尽相同,O(nlogn),O(nsqrt(n)),O(玄学)(也就是暴力) (数据比较水,所以一些暴力就过去了) 做法基本都是离线. 法一:AC自动机+暴力 对询问串建AC自动机,把主串往上跑. 匹配到了一个节点,就暴力跳fail,把沿途的点如果是询问串的结尾,ans++,并打上标记,防止重复计数. 一串1111