zoukankan      html  css  js  c++  java
  • 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
    ",ask[a].ans);
    	for(int a=1;a<=neko;a++)
    	{
    		printf("%d",ans[a]);
    		if(a<neko) printf(" ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Hopcroft-Carp 算法模板 自用
    (转)二分图匹配匈牙利算法与KM算法
    LightOJ
    最短路类型 (至今做过的)
    POJ
    POJ
    差分约束
    传递闭包(例题POJ3660)
    arrow,
    分辨率,
  • 原文地址:https://www.cnblogs.com/Sinogi/p/8689076.html
Copyright © 2011-2022 走看看