• P2336 [SCOI2012]喵星球上的点名


    题意

    我们将所有姓名串和点名串拼在一起,中间用原串中不会出现的数隔开,对每个点记录它是哪个串的。

    先考虑第一问:

    考虑如果点名串(s1)是某个姓名串(s2)的子串,则(s1)必定和(s2)的一个后缀(s2')(lcp)(s1)的长度,即:(lcp(s1,s2')=len(s1))

    对于一个点名串,以它作为前缀的后缀在后缀排序后必定是一个区间,我们可以二分得出,设为([l,r]),我们接下来就要统计([l,r])内出现的不同的姓名的个数,这是个经典问题,可以用(HH)的项链的的方法离线解决。

    再考虑第二问:

    我们可以算出每个点被多少询问区间覆盖,但这样会计重。

    我们从(1)(n)(n)是串长)扫描所有位置,同时维护可以对这个位置产生贡献的区间。具体说就是对于([l,r]),我们在扫到(l)时它开始产生贡献,我们对([l,r])区间(+1),在扫到(r+1)时,它不再产生贡献,我们对([l,r])区间(-1),这个可以用差分实现。

    现在考虑怎么算出当前位置(i)真正的贡献,即算出只包含(i),而不包含(i)所在的原串的其他点的区间。我们找到(last_{pos_i}),其中(pos_i)表示(i)所在原串,(last_{pos_i})表示上一个属于(pos_i)这个原串的位置,那么答案就是(sum_i-sum_{last_{pos_i}})

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxm=5*1e4+10;
    const int maxQ=1e5+10;
    const int maxl=1e6+10;
    int n,m,Q,num;
    int a[maxl],len[maxl],firpos[maxl],pos[maxl],last[maxm],ans1[maxQ],ans2[maxm];
    int sa[maxl],rk[maxl],oldrk[maxl],id[maxl],tmpid[maxl],cnt[maxl],lg[maxl];
    int height[maxl][20];
    struct Query{int l,r,id;}qr[maxQ];
    inline void reads(int now)
    {
    	firpos[now]=n+1;
    	scanf("%d",&len[now]);
    	for(int i=1;i<=len[now];i++)scanf("%d",&a[++n]),pos[n]=now;
    	a[++n]=now+10000;
    }
    inline bool cmp(Query x,Query y){return x.r<y.r;}
    inline bool check(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];}
    inline void SA_build()
    {
    	num=500000;
    	for(int i=1;i<=n;i++)cnt[rk[i]=a[i]]++;
    	for(int i=1;i<=num;i++)cnt[i]+=cnt[i-1];
    	for(int i=n;i;i--)sa[cnt[rk[i]]--]=i;
    	for(int t=1;t<=n;t<<=1)
    	{
    		int tot=0;
    		for(int i=n-t+1;i<=n;i++)id[++tot]=i;
    		for(int i=1;i<=n;i++)if(sa[i]>t)id[++tot]=sa[i]-t;
    		tot=0;
    		memset(cnt,0,sizeof(cnt));
    		for(int i=1;i<=n;i++)cnt[tmpid[i]=rk[id[i]]]++;
    		for(int i=1;i<=num;i++)cnt[i]+=cnt[i-1];
    		for(int i=n;i;i--)sa[cnt[tmpid[i]]--]=id[i];
    		memcpy(oldrk,rk,sizeof(rk));
    		for(int i=1;i<=n;i++)rk[sa[i]]=check(sa[i-1],sa[i],t)?tot:++tot;
    		num=tot;
    	}
    	for(int i=1,j=0;i<=n;i++)
    	{
    		if(j)j--;
    		while(a[i+j]==a[sa[rk[i]-1]+j])j++;
    		height[rk[i]][0]=j;
    	}
    	for(int j=1;j<=18;j++)
    		for(int i=1;i+(1<<j)-1<=n;i++)
    			height[i][j]=min(height[i][j-1],height[i+(1<<(j-1))][j-1]);
    }
    inline int query(int l,int r)
    {
    	l++;
    	int t=lg[r-l+1];
    	return min(height[l][t],height[r-(1<<t)+1][t]);
    }
    inline int findl(int id)
    {
    	int l=1,r=rk[firpos[id]]-1,res=rk[firpos[id]];
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(query(mid,rk[firpos[id]])<len[id])l=mid+1;
    		else res=mid,r=mid-1;
    	}
    	return res;
    }
    inline int findr(int id)
    {
    	int l=rk[firpos[id]]+1,r=n,res=rk[firpos[id]];
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(query(rk[firpos[id]],mid)<len[id])r=mid-1;
    		else res=mid,l=mid+1;
    	}
    	return res;
    }
    struct Tree_arry
    {
    	#define lowbit(x) (x&-x)
    	int a[maxl];
    	inline void clear(){memset(a,0,sizeof(a));}
    	inline void add(int x,int k){for(int i=x;i<=n;i+=lowbit(i))a[i]+=k;}
    	inline int query(int x){int res=0;for(int i=x;i;i-=lowbit(i))res+=a[i];return res;}
    }tr;
    int main()
    {
    	lg[0]=-1;
    	for(int i=1;i<=1e6;i++)lg[i]=lg[i>>1]+1;
    	scanf("%d%d",&m,&Q);
    	for(int i=1;i<=m;i++)reads(2*i-1),reads(2*i);
    	for(int i=1;i<=Q;i++)reads(2*m+i);
    	SA_build();
    	for(int i=1;i<=Q;i++)qr[i].l=findl(2*m+i),qr[i].r=findr(2*m+i),qr[i].id=i;
    	sort(qr+1,qr+Q+1,cmp);
    	for(int i=1,j=1;i<=Q;i++)
    	{
    		while(j<=qr[i].r)
    		{
    			if(pos[sa[j]]<=2*m)
    			{
    				if(last[(pos[sa[j]]+1)>>1])tr.add(last[(pos[sa[j]]+1)>>1],-1);
    				last[(pos[sa[j]]+1)>>1]=j;
    				tr.add(j,1);
    			}
    			j++;
    		}
    		ans1[qr[i].id]=tr.query(qr[i].r)-tr.query(qr[i].l-1);
    	}
    	for(int i=1;i<=m;i++)last[i]=0;
    	tr.clear();
    	for(int i=1;i<=Q;i++)tr.add(qr[i].l,1);
    	for(int i=1,j=1;i<=n;i++)
    	{
    		while(j<=Q&&qr[j].r<i)tr.add(qr[j].l,-1),j++;
    		if(pos[sa[i]]<=2*m)
    		{
    			ans2[(pos[sa[i]]+1)>>1]+=tr.query(i)-tr.query(last[(pos[sa[i]]+1)>>1]);
    			last[(pos[sa[i]]+1)>>1]=i;	
    		}
    	} 
    	for(int i=1;i<=Q;i++)printf("%d
    ",ans1[i]);
    	for(int i=1;i<=m;i++)printf("%d ",ans2[i]);
    	return 0;
    }
    
  • 相关阅读:
    Redhat7.0版本下双网卡绑定
    Zabbix3.4 Proxy搭建
    Centos7 + Mariadb主从配置
    Cacti找回管理员密码
    2017科鲁兹钥匙电池更换
    Failed to set locale, defaulting to C.UTF-8 centos8.2报错
    centos8如何重启网络服务
    gem install报错 ruby升级
    vmware fusion 11.0.0激活
    转载 centos8.1网络重启
  • 原文地址:https://www.cnblogs.com/nofind/p/12084157.html
Copyright © 2020-2023  润新知