bzoj 4199: [Noi2015]品酒大会 后缀树
题目大意:
给定一个长为n的字符串,每个下标有一个权\(w_i\),定义下标\(i,j\)是r相似的仅当\(r \leq LCP(suf(i),suf(j))\)且这个相似的权为\(w_i,w_j\)
分别求出所有满足1 .. r相似的下标对数,及最大权.
题解:
我们发现这道题可以在后缀树上瞎搞
我们知道:\(LCP(suf(i),suf(j)) = len(lca(i,j))\)
所以我们可以对后缀树上的所有节点dp一下,求出每个点的子树包含的点对数
同时dp出子树中存在的权的最大值,次大值,最小值,次小值
然后累加答案即可.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch = getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 1000010;
struct Edge{
int to,next;
}G[maxn];
int head[maxn],cnt;
void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
struct Node{
int nx[26];
int len,fa;
}T[maxn];
int last,nodecnt = 0,n;
int a[maxn],siz[maxn],mx[maxn],cmx[maxn];
int mn[maxn],cmn[maxn];
inline void insert(char cha,int i){
int c = cha - 'a',cur = ++ nodecnt,p;
T[cur].len = T[last].len + 1;
for(p = last;p != -1 && !T[p].nx[c];p = T[p].fa) T[p].nx[c] = cur;
if(p == -1) T[cur].fa = 0;
else{
int q = T[p].nx[c];
if(T[q].len == T[p].len + 1) T[cur].fa = q;
else{
int co = ++ nodecnt;T[co] = T[q];T[co].len = T[p].len + 1;
for(;p != -1 && T[p].nx[c] == q;p = T[p].fa) T[p].nx[c] = co;
T[cur].fa = T[q].fa = co;
}
}
siz[last = cur]++;
mx[cur] = mn[cur] = a[i];
}
ll num[maxn];
char s[maxn];
ll ans1[maxn],ans2[maxn];
inline void update(int &x,int &y,int z){
if(z >= x) y = x,x = z;
else if(z >= y) y = z;
}
inline void downpdate(int &x,int &y,int z){
if(z <= x) y = x,x = z;
else if(z <= y) y = z;
}
#define v G[i].to
void dfs(int u,int fa){
for(int i = head[u];i;i = G[i].next){
if(v == fa) continue;
dfs(v,u);
num[u] += 1LL*siz[u]*siz[v];
siz[u] += siz[v];
update(mx[u],cmx[u],mx[v]);update(mx[u],cmx[u],cmx[v]);
downpdate(mn[u],cmn[u],mn[v]);
downpdate(mn[u],cmn[u],cmn[v]);
}
if(mx[u] != mx[maxn-1] && cmx[u] != cmx[maxn-1]){
ans2[T[u].len] = max(ans2[T[u].len],max(1LL*mx[u]*cmx[u],1LL*mn[u]*cmn[u]));
}
ans1[T[u].len] += num[u];
}
#undef v
int main(){
memset(mx,-0x3f,sizeof mx);memset(cmx,-0x3f,sizeof cmx);
memset(mn,0x3f,sizeof mn);memset(cmn,0x3f,sizeof cmn);
memset(ans2,-0x3f,sizeof ans2);
T[last = nodecnt = 0].fa = -1;
read(n);scanf("%s",s);
for(int i=0;i<n;++i) read(a[i]);
reverse(s,s+n);reverse(a,a+n);
for(int i=0;i<n;++i) insert(s[i],i);
for(int i=1;i<=nodecnt;++i) add(T[i].fa,i);
dfs(0,0);
for(int i=n-2;i>=0;--i){
ans1[i] += ans1[i+1];
ans2[i] = max(ans2[i],ans2[i+1]);
}
for(int i=0;i<n;++i){
if(ans2[i] == ans2[maxn-1]) ans2[i] = 0;
printf("%lld %lld\n",ans1[i],ans2[i]);
}
getchar();getchar();
return 0;
}
bzoj 4199: [Noi2015]品酒大会 后缀树的更多相关文章
- uoj 131/bzoj 4199 [NOI2015]品酒大会 后缀树+树d
题目大意 见uoj131 分析 题目的提示还是很明显的 \(r\)相似就就代表了\(0...r-1\)相似 建出后缀树我们能dfs算出答案 再后缀和更新一下即可 注意 细节挺多的,但数据很良心 不然我 ...
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- BZOJ.4199.[NOI2015]品酒大会(后缀自动机 树形DP)
BZOJ 洛谷 后缀数组做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 只考虑求极长相同子串,即所有后缀之间的LCP. 而后缀的LCP在后缀树的LCA处.同差异这道题,在每个点处 ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
- BZOJ 4199: [Noi2015]品酒大会( 后缀数组 + 并查集 )
求出后缀数组后, 对height排序, 从大到小来处理(r相似必定是0~r-1相似), 并查集维护. 复杂度O(NlogN + Nalpha(N)) ------------------------- ...
- BZOJ 4199: [Noi2015]品酒大会 后缀自动机_逆序更新
一道裸题,可以考虑自底向上去更新方案数与最大值. 没啥难的 细节........ Code: #include <cstdio> #include <algorithm> #i ...
- bzoj 4199: [Noi2015]品酒大会
Description 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手&quo ...
- 【刷题】BZOJ 4199 [Noi2015]品酒大会
Description 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手&quo ...
- [BZOJ]4199: [Noi2015]品酒大会(后缀数组+笛卡尔树)
Time Limit: 10 Sec Memory Limit: 512 MB Description Input Output Sample Input 10 ponoiiipoi 2 1 4 7 ...
随机推荐
- ASIHTTP
本文转载至 http://www.th7.cn/Program/IOS/201303/128223.shtml 向服务器端上传数据 ASIFormDataRequest ,模拟 Form表单提 ...
- 【BZOJ2844】albus就是要第一个出场 高斯消元求线性基
[BZOJ2844]albus就是要第一个出场 Description 已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2 ...
- nginx学习之反向代理篇(六)
在本节,你将学会: --如何根据不同的协议,将请求转发到后端服务器: --修改发送到后端服务器的请求头: --以及配置是否buffering从后端服务器返回来的响应. 1. 将请求转发给后端服务器 当 ...
- Java基础 - 变量转换
在java中变量转发分为两种,隐式转换和强制转换 隐式转换: byte a = 10; int b = 20; byte c = a + b; // 该方法会报错,转换过程中字节数只能从小变大,不能从 ...
- 我的Android进阶之旅------>MIME类型大全
今天在实现一个安装apk的代码中看到一段代码为:application/vnd.android.package-archive,不知其意,所以百度了一下,了解到这是一种MIME的类型,代表apk类型. ...
- JVM垃圾回收时的可触及性
可触及的 1.从根节点可以触及到这个对象可复活的 1.一旦所有引用被释放,就是可复活状态 2.因为在finalize()中可能复活该对象不可触及的 1.在finalize()后,可能会进入不可触及状态 ...
- mongodb 的注意点
昨天同事安装mongodb遇到了些问题,问了下我,后拉发现都是些细节没注意(讲道理这应该是很简单,一顿操作就ok的事情) 首先,下载 mongo包, 然后 ,解压安装, 启动之. 问题就出现在他后台启 ...
- DAS、NAS、SAN
目前磁盘存储市场上,存储分类(如下表一)根据服务器类型分为:封闭系统的存储和开放系统的存储,封闭系统主要指大型机,AS400等服务器, 开放系统指基于包括Windows.UNIX.Linux等操作系统 ...
- MyBatis:学习笔记(4)——动态SQL
MyBatis:学习笔记(4)——动态SQL 如果使用JDBC或者其他框架,很多时候需要你根据需求手动拼装SQL语句,这是一件非常麻烦的事情.MyBatis提供了对SQL语句动态的组装能力,而且他只有 ...
- Ruby 循环
Ruby while 语句: 语法: while conditional [do] codeend 执行代码当条件为true时.while循环的条件是代码中的保留字,换行,反斜杠()或一个分号隔开. ...