【NOI2015】品酒大会

后缀自动机+线段树乱搞竟然1A,神奇…

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=(n);i++)
#define rep2(i,k,n) for(int i=k;i>=(n);i--)
#define ls x<<1
#define rs x<<1|1
using namespace std;
typedef long long ll;
const int N=600005;
const int inf=0x7f7f7f7f;
const ll inf2=0x7f7f7f7f7f7f7f7full;

struct E{
    int to,next;E(int to=0,int next=0):to(to),next(next){}
}edge[N];
int head[N],btot=0;
void add(int x,int y){
    edge[++btot]=E(y,head[x]);head[x]=btot;
}
char s[N];
int a[N],n,ch[N][26],len[N],par[N],val[N],last=0,tot=0,sum[N];
ll v[N];
struct data{
    ll mx[2];
    ll mn[2];
    data(){mx[0]=mx[1]=-inf;mn[0]=mn[1]=inf;}
}D[N];
void up(data& a,data b){
    data c;
    int op1,op2;

    op1=op2=0;
    rep(i,0,1)c.mx[i]=a.mx[op1]>b.mx[op2] ? a.mx[op1++] : b.mx[op2++];

    op1=op2=0;
    rep(i,0,1)c.mn[i]=a.mn[op1]<b.mn[op2] ? a.mn[op1++] : b.mn[op2++];

    a=c;
}
void ins(int c,int i){int p=last,x,q,nq;
    last=x=++tot;
    len[x]=len[p]+1;
    val[x]=1;
    v[x]=a[i];
    for(;!ch[p][c];p=par[p])ch[p][c]=x;
    if(ch[p][c]!=x){
        q=ch[p][c];
        if(len[q]==len[p]+1)par[x]=q;
        else{
            nq=++tot;
            len[nq]=len[p]+1;
            par[nq]=par[q];
            memcpy(ch[nq],ch[q],sizeof(ch[q]));
            par[q]=par[x]=nq;
            for(;ch[p][c]==q;p=par[p])ch[p][c]=nq;      
        }
    }
}
ll mx[N<<2],ad[N<<2];
void update(int x,int l,int r,int ql,int qr,ll Sum,ll Mx){
    if(ql<=l && r<=qr){
        ad[x]+=Sum;mx[x]=max(mx[x],Mx);return;
    }int mid=(l+r)>>1;
    if(ql<=mid)update(ls,l,mid,ql,qr,Sum,Mx);
    if(qr>mid)update(rs,mid+1,r,ql,qr,Sum,Mx);
}
ll ans_sum,ans_mx;
void query(int x,int l,int r,int k){
    ans_sum+=ad[x];
    ans_mx=max(ans_mx,mx[x]);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(k<=mid)query(ls,l,mid,k);
    else query(rs,mid+1,r,k);
}
void dp(int x){
    sum[x]=val[x];
    if(v[x]<inf){
        D[x].mx[0]=D[x].mn[0]=v[x];
    }
    int ok=0;
    for(int i=head[x];i;i=edge[i].next){
        int v=edge[i].to;
        dp(v);
        sum[x]+=sum[v];
        up(D[x],D[v]);
        ok++;
    }
    ll V=max(D[x].mx[0]*D[x].mx[1],D[x].mn[0]*D[x].mn[1]);
    if(ok && x)
    update(1,0,n,len[par[x]]+1,len[x],1ll*sum[x]*(sum[x]-1)/2,V);
    else if(!x)
    update(1,0,n,0,0,1ll*sum[x]*(sum[x]-1)/2,V);
}
void init(){
    rep(i,1,tot)add(par[i],i);
    memset(mx,-0x7f,sizeof(mx));
    dp(0);
}
int main(){
//  freopen("in.in","r",stdin);
//  freopen("out.out","w",stdout);
    scanf("%d",&n);
    scanf("%s",s+1);rep(i,1,n)scanf("%d",&a[i]);
    int l=n/2;
    rep(i,1,l)
    swap(s[i],s[n-i+1]),swap(a[i],a[n-i+1]);
    memset(v,0x7f,sizeof(v));
    rep(i,1,n)
    ins(s[i]-'a',i);
    init();
    rep(i,0,n-1){
        ans_sum=0,ans_mx=-inf2;
        query(1,0,n,i);
        if(!ans_sum)ans_mx=0;
        printf("%lld %lld\n",ans_sum,ans_mx);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值