题解 P2178 【[NOI2015]品酒大会】

y2823774827y

2019-03-12 10:53:11

Solution

### **$\Longrightarrow\Longrightarrow\Longrightarrow$[更好的阅读体验](https://www.cnblogs.com/y2823774827y/p/10515232.html)** 后缀数组一眼题系列 $r$相似用$height$数组处理,每次按$height$分裂区间,显然是有单调性的 所求的$r_0^{n-1}$,$O(n^2)$是过不了的 利用单调性,上烂大街的离线并查集 并查集要维护:大小,最大值,次大值,最小值,次小值(由于这里$a_i$为整数,所以答案可能由最小值与次小值贡献) 细节还是挺多的 ```cpp #include<bits/stdc++.h> #include<vector> using namespace std; typedef long long LL; inline LL Read(){ LL 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<<3)+(x<<1)+c-'0', c=getchar(); return x*f; } const LL maxn=1e6+9,inf=(1e18+1); LL n,ans,sum,va,m; LL c[maxn],x[maxn],sa[maxn],y[maxn],size[maxn],fa[maxn],rk[maxn],hei[maxn],w[maxn],tmp[maxn][2]; LL mx[maxn],cx[maxn],mi[maxn],ci[maxn]; bool visit[maxn],vx[maxn],vi[maxn]; char s[maxn]; inline void Get_sa(){ for(LL i=1;i<=n;++i) ++c[x[i]=(LL)(s[i]-'a'+1)]; for(LL i=2;i<=m;++i) c[i]+=c[i-1]; for(LL i=n;i>=1;--i) sa[c[x[i]]--]=i; for(LL len=1;len<=n;len<<=1){ LL num(0); for(LL i=n-len+1;i<=n;++i) y[++num]=i; for(LL i=1;i<=n;++i) if(sa[i]>len) y[++num]=sa[i]-len; for(LL i=1;i<=m;++i) c[i]=0; for(LL i=1;i<=n;++i) ++c[x[i]]; for(LL i=2;i<=m;++i) c[i]+=c[i-1]; for(LL i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0; memcpy(y,x,sizeof(x)); x[sa[1]]=num=1; for(LL i=2;i<=n;++i) x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+len]==y[sa[i-1]+len])?num:++num; if(num==n) break; m=num; } for(LL i=1;i<=n;++i) rk[sa[i]]=i; LL ret(0); for(LL i=1;i<=n;++i){ if(ret) --ret; LL j(sa[rk[i]-1]); while(s[j+ret]==s[i+ret]) ++ret; hei[rk[i]]=ret; } } LL Get_f(LL x){ return fa[x]==x?x:fa[x]=Get_f(fa[x]); } inline void Del(LL x){ sum-=((size[x]-1)*size[x])/2; } inline void Merge(LL x,LL y){ fa[x]=y; if(mx[x]>mx[y]){ cx[y]=mx[y]; mx[y]=mx[x]; if(vx[x] && cx[x]>cx[y]) cx[y]=cx[x]; }else cx[y]=(vx[y]?max(cx[y],mx[x]):mx[x]); if(mi[x]<mi[y]){ ci[y]=mi[y]; mi[y]=mi[x]; if(vi[x] && ci[x]<ci[y]) ci[y]=ci[x]; }else ci[y]=(vi[y]?min(ci[y],mi[x]):mi[x]); vx[y]=vi[y]=true; size[y]+=size[x]; sum+=((size[y]-1)*size[y]>>1); ans=max(ans,max(mx[y]*cx[y],mi[y]*ci[y])); } vector<LL>mark[maxn]; int main(){ n=Read(); scanf(" %s",s+1); for(LL i=1;i<=n;++i) w[i]=Read(); m=26; Get_sa(); for(LL i=1;i<=n;++i) mark[hei[i]].push_back(i); for(LL i=1;i<=n;++i) fa[i]=i; for(LL i=1;i<=n;++i){ mx[i]=mi[i]=w[i]; vx[i]=vi[i]=false; } ans=-inf; for(LL i=1;i<=n;++i) size[i]=1; for(LL i=n-1;i>=0;--i){ for(LL j=0;j<mark[i].size();++j){ LL x(sa[mark[i][j]]); visit[x]=true; LL sax(rk[x]), nxt(sa[sax+1]),pre(sa[sax-1]); LL fy(Get_f(pre)); Del(x); Del(fy); Merge(x,fy); } tmp[i][0]=sum; tmp[i][1]=(ans<=-inf?0:ans); } for(LL i=0;i<n;++i) printf("%lld %lld\n",tmp[i][0],tmp[i][1]); return 0; } ```