zoukankan      html  css  js  c++  java
  • 【洛谷P2336】喵星球上的点名

    题目

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

    思路

    把所有名字和点名全部串在一起,注意任意两个字符串中间要用不同的特殊字符隔开,然后跑一遍 SA,求出 height 并建立 ST 表。
    枚举每一个询问串,二分出它在 SA 数组上左右两个端点 (l,r) 使得 (lsim x) 的 LCP 和 (xsim r) 的 LCP 均等于该询问串的长度。那么 SA 上在 ([l,r]) 中所有的喵星人都会对这个询问产生一的贡献。问题转化为多次询问区间内有多少个不同颜色。按询问右端点从小到大排序后,对于每一个颜色记一个 (last) 表示最后出现这个颜色是在什么位置,在树状数组上每一个 (last) 处加一,然后询问树状数组中 ([l,r]) 的和即可。
    对于第二个询问,我们依然记录 (last[i]) 表示颜色 (i) 上一次出现的位置,枚举位置,如果这个位置是某个区间开头那么就在树状数组中将这个位置加一,如果是某个区间结尾就将这个区间开头减一。假设这个位置的颜色是 (i),那么询问 ((last[i],i]) 的和即可。
    时间复杂度 (O(n log n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=400010,LG=19;
    int n,nn,m,Q,s[N],sa[N],col[N],x[N],y[N],lg[N],c[N],height[N],rk[N],pos[N],len[N],ans1[N],ans2[N],last[N],rmq[N][LG+1];
    vector<int> qry[N];
    
    struct Query
    {
    	int l,r,id;
    }ask[N];
    
    bool cmp(Query x,Query y)
    {
    	return x.r<y.r;
    }
    
    void init(int k,int t=-1)
    {
    	if (t==-1) scanf("%d",&t);
    	while (t--)
    	{
    		scanf("%d",&s[++n]);
    		s[n]++; col[n]=k;
    	}
    	s[++n]=++x[0];
    }
    
    void SA()
    {
    	for (int i=1;i<=n;i++) x[i]=s[i],c[x[i]]++;
    	for (int i=2;i<=m;i++) c[i]+=c[i-1];
    	for (int i=n;i>=1;i--) sa[c[x[i]]--]=i;
    	for (int k=1;k<=n;k<<=1)
    	{
    		int num=0;
    		for (int i=n-k+1;i<=n;i++) y[++num]=i;
    		for (int i=1;i<=n;i++) if (sa[i]>k) y[++num]=sa[i]-k;
    		for (int i=1;i<=m;i++) c[i]=0;
    		for (int i=1;i<=n;i++) c[x[i]]++;
    		for (int i=2;i<=m;i++) c[i]+=c[i-1];
    		for (int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0;
    		swap(x,y);
    		x[sa[1]]=1; num=1;
    		for (int i=2;i<=n;i++)
    			x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? num : ++num;
    		m=num;
    		if (n==m) break;
    	}
    }
    
    void geth()
    {
    	for (int i=1;i<=n;i++) rk[sa[i]]=i;
    	for (int i=1,k=0;i<=n;i++)
    	{
    		if (k) k--;
    		int j=sa[rk[i]-1];
    		while (s[i+k]==s[j+k]) k++;
    		height[rk[i]]=k;
    	}
    }
    
    void getst()
    {
    	for (int i=1;i<=n;i++) rmq[i][0]=height[i];
    	for (int j=1;j<=LG;j++) 
    		for (int i=1;i+(1<<j)-1<=n;i++)
    			rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);
    }
    
    struct BIT
    {
    	int c[N];
    	
    	void add(int x,int v)
    	{
    		for (int i=x;i<=n;i+=i&-i)
    			c[i]+=v;
    	}
    	
    	int query(int x)
    	{
    		int sum=0;
    		for (int i=x;i;i-=i&-i)
    			sum+=c[i];
    		return sum;
    	}
    }bit;
    
    int binary1(int x,int t)
    {
    	int l=1,r=x-1;
    	while (l<=r)
    	{
    		int mid=(l+r)>>1,k=lg[x-mid];
    		if (min(rmq[mid+1][k],rmq[x-(1<<k)+1][k])==t) r=mid-1;
    			else l=mid+1;
    	}
    	return r+1;
    }
    
    int binary2(int x,int t)
    {
    	int l=x+1,r=n;
    	while (l<=r)
    	{
    		int mid=(l+r)>>1,k=lg[mid-x];
    		if (min(rmq[x+1][k],rmq[mid-(1<<k)+1][k])==t) l=mid+1;
    			else r=mid-1;
    	}
    	return l-1;
    }
    
    int main()
    {
    	scanf("%d%d",&nn,&Q);
    	x[0]=2e5; lg[1]=0;
    	for (int i=2;i<N;i++)
    		lg[i]=lg[i>>1]+1;
    	for (int i=1;i<=nn;i++) init(i),init(i);
    	for (int i=1;i<=Q;i++)
    	{
    		pos[i]=n+1; scanf("%d",&len[i]);
    		init(0,len[i]);
    	}
    	x[0]=0; m=4e5;
    	SA(); geth(); getst();
    	for (int i=1;i<=Q;i++)
    	{
    		ask[i].l=binary1(rk[pos[i]],len[i]);
    		ask[i].r=binary2(rk[pos[i]],len[i]);
    		ask[i].id=i;
    	}
    	sort(ask+1,ask+1+Q,cmp);
    	for (int i=1,j=1;i<=Q;i++)
    	{
    		for (;j<=ask[i].r;j++)
    		{
    			if (!col[sa[j]]) continue;
    			if (last[col[sa[j]]]) bit.add(last[col[sa[j]]],-1);
    			bit.add(j,1);
    			last[col[sa[j]]]=j;
    		}
    		ans1[ask[i].id]=bit.query(ask[i].r)-bit.query(ask[i].l-1);
    	}
    	memset(bit.c,0,sizeof(bit.c));
    	memset(last,0,sizeof(last));
    	for (int i=1;i<=Q;i++)
    	{
    		qry[ask[i].l].push_back(i);
    		qry[ask[i].r+1].push_back(i);
    	}
    	for (int i=1;i<=n;i++)
    	{
    		for (int j=0;j<qry[i].size();j++)
    		{
    			if (ask[qry[i][j]].l==i) bit.add(i,1);
    			if (ask[qry[i][j]].r==i-1) bit.add(ask[qry[i][j]].l,-1);
    		}
    		if (col[sa[i]])
    		{
    			ans2[col[sa[i]]]+=bit.query(i)-bit.query(last[col[sa[i]]]);
    			last[col[sa[i]]]=i;
    		}
    	}
    	for (int i=1;i<=Q;i++)
    		printf("%d
    ",ans1[i]);
    	for (int i=1;i<=nn;i++)
    		printf("%d ",ans2[i]);
    	return 0;
    }
    
  • 相关阅读:
    再说Play!framework http://hsfgo.iteye.com/blog/806974
    PlayFramework 1 自定义标签 -- FastTags http://unmi.cc/category/javajee/playframework/
    [译] 第三十天:Play Framework
    你可以使用 play framework 做5件很爽的事情http://www.anool.net/?p=629
    Play常用代码片段 http://www.anool.net/?p=625
    Play 内置模板标签(1.2.3版本)http://www.anool.net/?p=617
    for what? while 与 until 差在哪?-- Shell十三问<第十三问>
    你要 if 还是 case 呢?-- Shell十三问<第十二问>
    > 与 < 差在哪?-- Shell十三问<第十一问>
    && 与 || 差在哪?-- Shell十三问<第十问>
  • 原文地址:https://www.cnblogs.com/stoorz/p/14045946.html
Copyright © 2011-2022 走看看