zoukankan      html  css  js  c++  java
  • BZOJ4199 NOI2015品酒大会(后缀树)

      利用SAM建出后缀树,树上每个节点计算一下|right|、right集合中ai的最大、次大、最小、次小值即可。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 600010
    #define inf 1000000010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,a[N],son[N][26],fail[N],len[N],size[N],mx[N],mx2[N],mn[N],mn2[N],cnt=1,last=1;
    ll ans[N],tot[N];
    char s[N];
    int p[N],t;
    struct data{int to,nxt;
    }edge[N<<1];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void ins(int c)
    {
    	int x=++cnt,p=last;last=x;len[x]=len[p]+1;size[x]=1;mx[x]=mn[x]=a[len[x]];mx2[x]=-inf,mn2[x]=inf;
    	while (!son[p][c]) son[p][c]=x,p=fail[p];
    	if (!p) fail[x]=1;
    	else
    	{
    		int q=son[p][c];
    		if (len[p]+1==len[q]) fail[x]=q;
    		else
    		{
    			int y=++cnt;mx[y]=mx2[y]=-inf,mn[y]=mn2[y]=inf;
    			len[y]=len[p]+1;
    			memcpy(son[y],son[q],sizeof(son[q]));
    			fail[y]=fail[q],fail[q]=fail[x]=y;
    			while (son[p][c]==q) son[p][c]=y,p=fail[p];
    		}
    	}
    }
    void dfs(int k)
    {
    	for (int i=p[k];i;i=edge[i].nxt) 
    	{
    		dfs(edge[i].to);
    		size[k]+=size[edge[i].to];
    		tot[len[k]]-=1ll*size[edge[i].to]*(size[edge[i].to]-1)>>1;
    		if (mx2[edge[i].to]>mx[k]) mx[k]=mx[edge[i].to],mx2[k]=mx2[edge[i].to];
    		else if (mx[edge[i].to]>mx[k]) mx2[k]=max(mx2[edge[i].to],mx[k]),mx[k]=mx[edge[i].to];
    		else mx2[k]=max(mx2[k],mx[edge[i].to]);
    		if (mn2[edge[i].to]<mn[k]) mn[k]=mn[edge[i].to],mn2[k]=mn2[edge[i].to];
    		else if (mn[edge[i].to]<mn[k]) mn2[k]=min(mn2[edge[i].to],mn[k]),mn[k]=mn[edge[i].to];
    		else mn2[k]=min(mn2[k],mn[edge[i].to]);
    	}
    	tot[len[k]]+=1ll*size[k]*(size[k]-1)>>1;
    	if (mx2[k]>-inf) ans[len[k]]=max(ans[len[k]],1ll*mx[k]*mx2[k]);
    	if (mn2[k]<inf) ans[len[k]]=max(ans[len[k]],1ll*mn[k]*mn2[k]);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    	const char LL[]="%I64d
    ";
    #else
    	const char LL[]="%lld
    ";
    #endif
    	n=read();mx[1]=mx2[1]=-inf,mn[1]=mn2[1]=inf;
    	scanf("%s",s+1);reverse(s+1,s+n+1);
    	for (int i=1;i<=n;i++) a[i]=read();reverse(a+1,a+n+1);
    	for (int i=1;i<=n;i++) ins(s[i]-'a');
    	for (int i=2;i<=cnt;i++) addedge(fail[i],i);
    	memset(ans,200,sizeof(ans));
    	dfs(1);
    	for (int i=n-1;i>=0;i--) ans[i]=max(ans[i],ans[i+1]),tot[i]+=tot[i+1];
    	for (int i=0;i<n;i++) if (tot[i]==0) ans[i]=0;
    	for (int i=0;i<n;i++) printf("%lld %lld
    ",tot[i],ans[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    转载文章:用.NET开发MSN聊天机器人 MSN聊天机器人开发揭秘
    ppc全屏程序(转)
    表设计中遇到的多对多的关系解决方案 (zt)
    using ZedGraph
    DataTable.Select(expression)
    你认识它吗?什么是QR码?
    分享《Windows Mobile平台应用与开发》源代码
    收藏信息
    六世喇嘛仓央嘉措诗集
    使用Axis开发Web Service程序
  • 原文地址:https://www.cnblogs.com/Gloid/p/10808260.html
Copyright © 2011-2022 走看看