bzoj4199&uoj131: [Noi2015]品酒大会

传送门:http://uoj.ac/problem/131

思路:先求出height,然后根据排名重新给后缀标号,按height从大到小做,每次合并i和i-1,用并查集维护,更新答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
const int maxn=300010;
using namespace std;
typedef long long ll;
int n,a[maxn];ll ans[maxn],cnt[maxn];char s[maxn];
struct orz{int h,pos;}cls[maxn];
bool cmp(orz a,orz b){return a.h>b.h;}

struct Tufs{
	int maxs[maxn],mins[maxn],fa[maxn],siz[maxn];
	int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
	void merge(int x,int y){
		x=getfa(x),y=getfa(y),fa[y]=x;
		maxs[x]=max(maxs[x],maxs[y]);
		mins[x]=min(mins[x],mins[y]);
		siz[x]+=siz[y];
	}
}ufs;

struct Suffix_Array{
	int sa[maxn],rank[maxn],t1[maxn],t2[maxn],sum[maxn],h[maxn];
	void getsa(){
		int *x=t1,*y=t2,m=255,p=0;
		for (int i=1;i<=n;i++) sum[x[i]=s[i]]++;
		for (int i=1;i<=m;i++) sum[i]+=sum[i-1];
		for (int i=n;i;i--) sa[sum[x[i]]--]=i;
		for (int j=1;p<n;j<<=1,m=p){
			p=0;
			for (int i=n-j+1;i<=n;i++) y[++p]=i;
			for (int i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j;
			memset(sum,0,sizeof(sum));
			for (int i=1;i<=n;i++) sum[x[y[i]]]++;
			for (int i=1;i<=m;i++) sum[i]+=sum[i-1];
			for (int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];
			swap(x,y),x[sa[1]]=p=1;
			for (int i=2;i<=n;i++){
				if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+j]!=y[sa[i-1]+j]) p++;
				x[sa[i]]=p;
			}
		}
		
		memcpy(rank,x,sizeof(rank));
	}
	void geth(){
		for (int i=1,j=0;i<=n;i++){
			if (rank[i]==1) continue;
			while (s[i+j]==s[sa[rank[i]-1]+j]) j++;
			h[rank[i]]=j;
			if (j) j--;
		}
	}
	void work(){
		memset(ans,128,sizeof(ans));
		for (int i=2;i<=n;i++) cls[i-1]=(orz){h[i],i};
		sort(cls+1,cls+n,cmp);
		for (int i=cls[1].h,j=1;i>=0;i--){
			ans[i]=ans[i+1],cnt[i]=cnt[i+1];
			for (;j<n&&cls[j].h==i;j++){
				int x=ufs.getfa(cls[j].pos),y=ufs.getfa(cls[j].pos-1);
				ans[i]=max(ans[i],1ll*ufs.maxs[x]*ufs.maxs[y]);
				ans[i]=max(ans[i],1ll*ufs.mins[x]*ufs.mins[y]);
				cnt[i]+=1ll*ufs.siz[x]*ufs.siz[y];
				ufs.merge(x,y);
			}
		}
		for (int i=0;i<n;i++)
			if (cnt[i]) printf("%lld %lld\n",cnt[i],ans[i]);
			else puts("0 0");
	}
}SA;

int main(){
	scanf("%d%s",&n,s+1);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	SA.getsa(),SA.geth();
	for (int i=1;i<=n;i++) ufs.fa[i]=i,ufs.mins[SA.rank[i]]=ufs.maxs[SA.rank[i]]=a[i],ufs.siz[i]=1;
	SA.work();
	return 0;
}


posted @ 2015-08-16 16:23  orzpps  阅读(121)  评论(0编辑  收藏  举报