利用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\n";
#else
const char LL[]="%lld\n";
#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\n",tot[i],ans[i]);
return 0;
}

  

BZOJ4199 NOI2015品酒大会(后缀树)的更多相关文章

  1. [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  2. uoj 131/bzoj 4199 [NOI2015]品酒大会 后缀树+树d

    题目大意 见uoj131 分析 题目的提示还是很明显的 \(r\)相似就就代表了\(0...r-1\)相似 建出后缀树我们能dfs算出答案 再后缀和更新一下即可 注意 细节挺多的,但数据很良心 不然我 ...

  3. bzoj 4199: [Noi2015]品酒大会 后缀树

    题目大意: 给定一个长为n的字符串,每个下标有一个权\(w_i\),定义下标\(i,j\)是r相似的仅当\(r \leq LCP(suf(i),suf(j))\)且这个相似的权为\(w_i,w_j\) ...

  4. [UOJ#131][BZOJ4199][NOI2015]品酒大会

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  5. 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集

    [BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...

  6. BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]

    4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...

  7. 【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合

    4199: [Noi2015]品酒大会 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 436  Solved: 243[Submit][Status] ...

  8. [NOI2015] 品酒大会 - 后缀数组,并查集,STL,启发式合并

    [NOI2015] 品酒大会 Description 对于每一个 \(i \in [0,n)\) 求有多少对后缀满足 LCP 长度 \(\le i\) ,并求满足条件的两个后缀权值乘积的最大值. So ...

  9. [bzoj4199][Noi2015]品酒大会_后缀自动机_后缀树_树形dp

    品酒大会 bzoj-4199 Noi-2015 题目大意:给定一个字符串,如果其两个子串的前$r$个字符相等,那么称这两个子串的开头两个位置$r$相似.如果两个位置勾兑在一起那么美味度为两个位置的乘积 ...

  10. 【bzoj4199】[Noi2015]品酒大会 后缀自动机求后缀树+树形dp

    题目描述(转自百度文库) 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒 ...

随机推荐

  1. 2018-2019-2 20165234 《网络对抗技术》 Exp7 网络欺诈防范

    Exp7  网络欺诈防范 实验内容 1. 简单应用SET工具建立冒名网站 2. ettercap DNS spoof 3. 结合应用两种技术,用DNS spoof引导特定访问到冒名网站 4. 请勿使用 ...

  2. 如何计算一个C/C++程序运行时间

    前两天要计算一个用C++实现的算法运行时间,就用了clock()这个函数.程序大体上如下: clock_t start,end; start = clock(); /*my code*/ end = ...

  3. mybatis设置Map空值返回

    mybatis时,设置Map返回,当值为空时属性也会没有 在application.properties中加入下面配置,将会解决这个问题. #当查询数据为空时字段返回为null,不加这个查询数据为空时 ...

  4. php如何生成 uuid(总结)

    php如何生成 uuid(总结) 一.总结 一句话总结: UUID的全拼为“Universally Unique Identifier”,可以译为“通用唯一识别码”. UUID是指在一台机器上生成的数 ...

  5. initGLWidgetAndViewer

    void initGLWidgetAndViewer() { osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::Vie ...

  6. Javescript——变量声明的区别

    原文链接:ES6 Syntax and Feature Overview View on GitHub Keyword Scope Hoisting Can Be Reassigned Can Be ...

  7. 隐藏Nginx、Apache、PHP的版本号

    Nginx: 在nginx配置文件nginx.conf中,加入以下代码: server_tokens off; Apache: 在apache配置文件httpd.conf中,加入以下代码: Serve ...

  8. react 问题记录三

    7.三元表达式 是否显示提交按钮(值运算用一对大括号包起来): {this.state.isTrue ? <FormItem style={{textAlign: 'right',marginT ...

  9. render()中添加js函数

    方案一: { title: '操作', key: 'operation', render: (_, record) => ( <div> <Link to={`/hostMai ...

  10. Flutter easyrefresh示例 上拉加载+下拉刷新

    官方示例,简单改了下,实现功能为主. 代码如下: import 'dart:async'; import 'package:flutter/material.dart'; import 'packag ...