• BZOJ2754 [SCOI2012]喵星球上的点名 SA+莫队+树状数组


    题面

    戳这里

    题解

    首先先把所有给出的姓名和询问全部接在一起,建出(height)数组。

    某个串要包含整个询问串,其实就相当于某个串与询问串的(lcp)为询问串的长度。

    而两个后缀(Suffix_i)(Suffix_j)(lcp)(min(height_{rank_i+1},height_{rank_i+2},...,height_{rank_j}))

    所以和某个询问串的(lcp==)询问串的长度的后缀的(rank)肯定是连续的(往两边拓展(Min)肯定是单调不增的),我们可以用(st+)二分求出。

    然后第一问就可以转化为,区间内有多少个不同的数,莫队即可。

    对于第二问,我们可以对于每个点求出,有多少个区间包含它,但同时不包含在这个点前面且与它的值相同的点,先对每个区间按右端点(sort),然后扫过去,树状数组维护左端点即可。

    #include<bits/stdc++.h>
    #define For(i,x,y) for (int i=(x);i<=(y);i++)
    #define Dow(i,x,y) for (int i=(x);i>=(y);i--)
    #define cross(i,k) for (int i=first[k];i;i=last[i])
    using namespace std;
    typedef long long ll;
    inline ll read(){
        ll x=0;int ch=getchar(),f=1;
        while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
        if (ch=='-'){f=-1;ch=getchar();}
        while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    const int N = 3e5+10;
    struct node{
    	int len,pos,id,l,r,ans;
    }q[N];
    int n,m,cnt,len,a[N],id[N];
    inline void rd(){
    	n=read(),m=read();
    	For(i,1,n){
    		len=read();
    		For(j,1,len) a[++cnt]=read(),id[cnt]=i;
    		a[++cnt]=10000+2*i,len=read();
    		For(j,1,len) a[++cnt]=read(),id[cnt]=i;
    		a[++cnt]=10000+2*i+1;
    	}
    	For(i,1,m){
    		q[i].len=read(),q[i].pos=cnt+1,q[i].id=i;
    		For(j,1,q[i].len) a[++cnt]=read();
    		a[++cnt]=10000+2*(n+1)+i;
    	}
    	//For(i,1,cnt) printf("%6d ",a[i]);puts("");
    }
    int Max,sum[N],x[N],y[N],SA[N],Rank[N],height[N];
    inline void Radix_Sort(int n){
    	Max=0;
    	For(i,1,n) sum[x[i]]++,Max=max(Max,x[i]);
    	For(i,1,Max) sum[i]+=sum[i-1];
    	Dow(i,n,1) SA[sum[x[y[i]]]--]=y[i];
    	For(i,0,Max) sum[i]=0;
    }
    inline void GetSA(int n){
    	For(i,1,n) x[i]=a[i],y[i]=i;
    	Radix_Sort(n);
    	for (int i=1,p=0;p<n;i<<=1){
    		p=0;
    		For(j,n-i+1,n) y[++p]=j;
    		For(j,1,n) if (SA[j]>i) y[++p]=SA[j]-i;
    		Radix_Sort(n),swap(x,y),x[SA[1]]=p=1;
    		For(j,2,n) x[SA[j]]=(y[SA[j]]==y[SA[j-1]]&&y[SA[j]+i]==y[SA[j-1]+i])?p:++p;
    	}
    	For(i,1,n) Rank[SA[i]]=i;
    	int now=0;
    	For(i,1,n){
    		if (Rank[i]==1) continue;now=max(now-1,0);
    		for (int j=SA[Rank[i]-1];j+now<=n&&i+now<=n&&a[j+now]==a[i+now];now++);
    		height[Rank[i]]=now;
    	}
    	//For(i,1,n) printf("%6d ",Rank[i]);puts("");
    	//For(i,1,cnt) printf("%6d ",height[i]);puts("");
    }
    int p[N],Log[N],f[N][21];
    inline int Query(int l,int r){
    	int k=Log[r-l+1];
    	return min(f[l][k],f[r-p[k]+1][k]);
    }
    inline int Findl(int ql,int qr,int x){
    	int l=ql,r=qr,mid,ans=qr+1;
    	while (l<=r) mid=l+r>>1,(Query(mid,qr)>=x)?(r=mid-1,ans=mid):l=mid+1;
    	return ans;
    }
    inline int Findr(int ql,int qr,int x){
    	int l=ql,r=qr,mid,ans=ql-1;
    	while (l<=r) mid=l+r>>1,(Query(ql,mid)>=x)?(l=mid+1,ans=mid):r=mid-1;
    	return ans;
    }
    inline void GetQuery(int n){
    	For(i,1,n) Log[i]=log2(i),f[i][0]=height[i];
    	p[0]=1;For(i,1,Log[n]) p[i]=p[i-1]<<1;
    	For(j,1,Log[n])
    		For(i,1,n-p[j]+1) f[i][j]=min(f[i][j-1],f[i+p[j-1]][j-1]);
    	For(i,1,m) q[i].l=Findl(1,Rank[q[i].pos],q[i].len)-1,q[i].r=Findr(Rank[q[i].pos]+1,n,q[i].len);
    	//For(i,1,m) printf("%d %d %d
    ",q[i].l,q[i].r,Rank[q[i].pos]);
    }
    int blo,ans1[N],Pos[N];
    inline bool cmp(node a,node b){
    	if (Pos[a.l]==Pos[b.l]) return (Pos[a.l]&1)?a.r<b.r:a.r>b.r; 
    		else return Pos[a.l]<Pos[b.l];
    }
    int c[N],Ans;
    inline void Add(int x){
    	x=id[SA[x]];if (!x) return;
    	if (++c[x]==1) Ans++;
    }
    inline void Del(int x){
    	x=id[SA[x]];if (!x) return;
    	if (--c[x]==0) Ans--;
    }
    inline void work1(){
    	blo=sqrt(cnt);
    	For(i,1,cnt) Pos[i]=(i-1)/blo+1;
    	sort(q+1,q+1+m,cmp);
    	//For(i,1,m) printf("%d %d %d
    ",q[i].l,q[i].r,q[i].id);
    	//printf("%d %d
    ",m,cnt);
    	int l=q[1].l,r=q[1].r;
    	For(i,l,r) Add(i);
    	ans1[q[1].id]=Ans;
    	For(i,2,m){
    		while (l<q[i].l) Del(l++);
    		while (r>q[i].r) Del(r--);
    		while (l>q[i].l) Add(--l);
    		while (r<q[i].r) Add(++r);
    		ans1[q[i].id]=Ans;
    		//puts("");puts("");
    		//For(i,1,n) printf("%d ",ans2[i]);puts("");
    	}
    	For(i,1,m) printf("%d
    ",ans1[i]);
    }
    int ans2[N],last[N];
    struct BIT{
    	int c[N];
    	inline void Add(int x,int y){for (;x<=cnt;x+=x&(-x)) c[x]+=y;}
    	inline int query(int x){int ans=0;for (;x;x-=x&(-x)) ans+=c[x];return ans;}	
    }t;
    inline bool cmp2(node a,node b){return a.r<b.r;}
    inline void work2(){
    	sort(q+1,q+1+m,cmp2);
    	//For(i,1,m) printf("%d %d
    ",q[i].l,q[i].r); 
    	For(i,1,m) t.Add(q[i].l,1);
    	int now=1;
    	//For(i,1,cnt) printf("%d ",id[SA[i]]);puts("");
    	For(i,1,cnt){
    		if (!id[SA[i]]) continue;
    		while (q[now].r<i&&now<=m) t.Add(q[now++].l,-1);
    		if (now>m) break;
    		ans2[id[SA[i]]]+=t.query(i)-t.query(last[id[SA[i]]]),last[id[SA[i]]]=i;
    	}
    	For(i,1,n) printf("%d ",ans2[i]);
    }
    int main(){
    	rd(),GetSA(cnt),GetQuery(cnt),work1(),work2();
    }
    
  • 相关阅读:
    五分钟快速搭建Serverless免费邮件服务
    【Python基础编程240 ● 异常 ● 异常的跨函数传递】
    【Python基础编程239 ● 异常 ● 异常语句中else语句的使用】
    【Python基础编程238 ● 异常 ● 异常语句中else语句的使用】
    【Python基础编程237 ● 异常 ● 异常处理的基本格式:单独捕获单独处理】
    【Python基础编程236 ● 异常 ● 异常处理的基本格式】
    【Python基础编程235 ● 异常 ● 异常处理的基本格式】
    【Python基础编程234 ● 异常 ● 异常的概述】
    【Python基础编程233 ● 面向对象 ● 多态】
    【Python基础编程232 ● 面向对象 ● 静态方法】
  • 原文地址:https://www.cnblogs.com/zykykyk/p/9489757.html
Copyright © 2020-2023  润新知