BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay
BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay
Description
Input
Output
输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量
Sample Input
1 2 3 3 3 1 2
Sample Output
3
6
9
12
17
22
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100050
#define ls ch[p][0]
#define rs ch[p][1]
#define get(x) (ch[f[x]][1]==x)
typedef long long ll;
int n,ws[N],wv[N],wa[N],wb[N],rank[N],sa[N],height[N],r[N];
int f[N],ch[N][2],siz[N],rt,val[N],reimu;
//////////////////////////////////////////////
struct A {
int num,id,v;
}a[N];
bool cmp1(const A &x,const A &y){return x.num<y.num;}
bool cmp2(const A &x,const A &y){return x.id<y.id;}
///////////////////////////////////////////////
void build_suffix_array() {
int i,j,p,*x=wa,*y=wb,*t,m=n;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(j=p=1;p<n;j<<=1,m=p) {
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++) {
if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=p-1;
else x[sa[i]]=p++;
}
}
for(i=1;i<n;i++) rank[sa[i]]=i;
for(i=p=0;i<n-1;height[rank[i++]]=p)
for(p?p--:0,j=sa[rank[i]-1];r[i+p]==r[j+p];p++);
}
/////////////////////////////////////////////
int newnode(int x) {
siz[++reimu]=1; val[reimu]=x; return reimu;
}
void pushup(int p) {
siz[p]=siz[ls]+siz[rs]+1;
}
void rotate(int x) {
int y=f[x],z=f[y],k=get(x);
ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
ch[x][!k]=y; f[y]=x; f[x]=z;
if(z) ch[z][ch[z][1]==y]=x;
pushup(y); pushup(x);
if(rt==y) rt=x;
}
void splay(int x,int y) {
for(int fa;(fa=f[x])!=y;rotate(x))
if(f[fa]!=y)
rotate(get(x)==get(fa)?fa:x);
}
void insert(int x) {
int p=rt,l,r;
while(p) {
if(val[p]>=x) r=p,p=ls;
else l=p,p=rs;
}
splay(l,0); splay(r,rt);
ch[r][0]=newnode(x);
f[reimu]=r; pushup(r); pushup(l);
}
int pre(int x) {
int p=rt,ans;
while(p) {
if(val[p]>=x) p=ls;
else ans=p,p=rs;
}
return val[ans];
}
int nxt(int x) {
int p=rt,ans;
while(p) {
if(val[p]<=x) p=rs;
else ans=p,p=ls;
}
return val[ans];
}
/////////////////////////////////////////
struct ST {
int f[N][20],L[N];
void init() {
int i,j;
memset(f,0x3f,sizeof(f));
L[1]=0;
for(i=2;i<=n;i++) L[i]=L[i>>1]+1;
for(i=0;i<=n;i++) {
f[i][0]=height[i];
}
for(j=1;(1<<j)<=n;j++) {
for(i=0;i+(1<<j)-1<=n;i++) {
f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
}
}
int get_min(int l,int r) {
int len=L[r-l+1];
return min(f[l][len],f[r-(1<<len)+1][len]);
}
}S;
int main() {
scanf("%d",&n);
int i;
for(i=1;i<=n;i++) scanf("%d",&a[n-i+1].num),a[i].id=i;
sort(a+1,a+n+1,cmp1);
int j=0;a[0].num=23333443;
for(i=1;i<=n;i++) {
if(a[i].num!=a[i-1].num) j++;
a[i].v=j;
}
sort(a+1,a+n+1,cmp2);
for(i=0;i<n;i++) {
r[i]=a[i+1].v;
}
r[n++]=0;
build_suffix_array(); /*for(i=0;i<n;i++) printf("%d ",r[i]); puts("");
for(i=0;i<n;i++) printf("%d ",sa[i]); puts("");
for(i=0;i<n;i++) printf("%d ",height[i]); puts("");
for(i=0;i<n;i++) printf("%d ",rank[i]);puts("");*/ ll ans=0;
rt=newnode(-100000000);
ch[rt][1]=newnode(100000000);
f[ch[rt][1]]=rt;
pushup(rt); S.init();
for(i=n-2;i>=0;i--) {
ans+=n-i-1;
int pr=pre(rank[i]);
int tmp=0;
if(pr>=0) {
tmp=S.get_min(pr+1,rank[i]);
}
int nx=nxt(rank[i]);
if(nx<=n) {
tmp=max(tmp,S.get_min(rank[i]+1,nx));
}
ans-=tmp;
insert(rank[i]);
printf("%lld\n",ans);
}
}
/*
7
1 2 3 3 3 1 2
*/
BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay的更多相关文章
- bzoj千题计划283:bzoj4516: [Sdoi2016]生成魔咒(后缀数组)
http://www.lydsy.com/JudgeOnline/problem.php?id=4516 考虑在后面新加一个字母产生的影响 假设是第i个 如果不考虑重复,那么会增加i个不同的字符串 考 ...
- BZOJ4516 SDOI2016生成魔咒(后缀数组+平衡树)
一个字符串本质不同的子串数量显然是总子串数减去所有height值.如果一个个往里加字符的话,每次都会改动所有后缀完全没法做.但发现如果从后往前加的话,每次只会添加一个后缀.于是我们把字符串倒过来,每次 ...
- BZOJ4516 [Sdoi2016]生成魔咒 【后缀自动机】
题目 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例如 S=[1,2, ...
- cogs2223. [SDOI2016 Round1] 生成魔咒(后缀数组 hash 二分 set
题意:对一个空串每次在后面加一个字符,问每加完一次得到的字符串有几个不同的子串. 思路:每个子串都是某个后缀的前缀,对于每个后缀求出他能贡献出之前没有出现过的前缀的个数,答案累加就行. 要求每个后缀的 ...
- 2018.12.23 bzoj4516: [Sdoi2016]生成魔咒(后缀自动机)
传送门 samsamsam入门题. 题意简述:给出一个串让你依次插入字符,求每次插入字符之后不同子串的数量. 显然每次的变化量只跟新出现的nnn个后缀有关系,那么显然就是maxlenp−maxlenl ...
- [SDOI2016]生成魔咒(后缀自动机)
看一眼题.本质不同的字串数. 嘴角微微上扬. 每一次加一个数输出一个答案. 笑容渐渐消失. 等等,\(SAM\)好像也可以求本质不同的字串. 设当前字符串用\(x\)表示,每次插入完成后\(ans\) ...
- 【洛谷 P4070】 [SDOI2016]生成魔咒(后缀自动机)
题目链接 建出\(SAM\)后,不同子串个数就是\(\sum len(i)-len(fa(i))\) 因为\(SAM\)在线的,所以每加入一个字符就能直接加上其贡献,于是这道题就没了. 因为\(x\) ...
- BZOJ4516 SDOI2016生成魔咒(后缀自动机)
本质不同子串数量等于所有点的len-parent树上父亲的len的和.可以直接维护. #include<iostream> #include<cstdio> #include& ...
- [SDOI2016] 生成魔咒 - 后缀数组,平衡树,STL,时间倒流
[SDOI2016] 生成魔咒 Description 初态串为空,每次在末尾追加一个字符,动态维护本质不同的子串数. Solution 考虑时间倒流,并将串反转,则变为每次从开头删掉一个字符,即每次 ...
随机推荐
- SDWebImage底层实现原理
SDWebImage底层实现有沙盒缓存机制,主要由三块组成 1.内存图片缓存2.内存操作缓存3.磁盘沙盒缓存内部实现过程:第一步,下载SDWebImage,导入工程. 第二步,在需要的地方导入头文件 ...
- 深入理解SpringCloud之配置刷新
我们知道在SpringCloud中,当配置变更时,我们通过访问http://xxxx/refresh,可以在不启动服务的情况下获取最新的配置,那么它是如何做到的呢,当我们更改数据库配置并刷新后,如何能 ...
- [C#网络应用编程]1、对进程的操作
在.net中,Process类提供了对进程进行管理的各种方法. 一.获取进程集合的方法: Process[] myProcesses = Process.GetProcesses(); //获取本地 ...
- linux 系统centOS 7 怎么在线安装mysql
以下操作,注意空格,为避免出错,可以选择直接copy 第一步: 输入命令行 yum list installed | grep mysql 检查是否已经安装mysql 已安装输入 ...
- SSM博客
最近在写基于SSM 的博客,用的是spring+springmvc+mybatis搭建的,用的maven+github管理项目,目前完成了登录注册以及用户管理员的增删改查,后续的功能还需要完善,如何建 ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC八大类扩展(上篇)
lASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操 ...
- vue项目中解决type=”file“ change事件只执行一次的问题
问题描述 在最近的项目开发中遇到了这样的一个问题,当我上传了一个文件时,我将获取到的文件名清空后,却无法再次上传相同的文件 <template> <div class="h ...
- Scrapy爬虫框架补充内容三(代理及其基本原理介绍)
前言:(本文参考维基百科及百度百科所写) 当我们使用爬虫抓取数据时,有时会产生错误比如:突然跳出来了403 Forbidden 或者网页上出现以下提示:您的ip访问频率太高 或者时不时跳出一个验证码需 ...
- Centos下安装Python的问题汇总
Python下载地址(https://www.python.org/ftp/python/) 一.工具安装 1.Python的安装 tar vxf Python-2.7.13.tgz cd Pytho ...
- Nginx安装及配置
Nginx是一款速度快,功能强大的http以及反向代理服务器,经过简单的配置之后即可以用来托管页面. 不幸的是,和很多其他系统管理工具一样,相关的原理教程和配置说明文档都很少.虽然官方提供了一个wik ...