Time:2016.05.28
Author:xiaoyimi
转载注明出处谢谢


思路:
(考场上写的60分kmp……)
学过后缀数组的都知道,一个串里不同子串的个数=∑(n−sa[i]−height[i])∑(n-sa[i]-height[i])
对于问题中串每次插入一个数字,它实际上使长度增加了1,即∑n=n2=(n+1)2∑n=n^2=(n+1)^2,对答案的贡献是2n+1,注意这里的n不是总长,而是插入前的串的长度,而∑sa[i]=n(n−1)∑sa[i]=n(n-1),对答案的贡献是-n,所以每次增加的就是n+1,同时插入的数字会对相邻的height产生影响,并会产生新的两个height,查询排名这个东西可以用splay解决,求任意两个子串(实际上这里是后缀)的LCP直接预处理ST表就可以了
注意:
开long long,且处理后的串是倒转的,注意下标
代码:

#include<bits/stdc++.h>
#define M 100003
#define LL long long
using namespace std;
int n,root;
int w[M],sa[M],rank[M],tmp[M],cnt[M],id[M],height[M],f[M][18];
LL ans;
struct Splay{int data,ch[2],fa,siz;}a[M];
struct disc{int data,id;}b[M];
bool cmp(disc x,disc y){return x.data<y.data;};
int in()
{int t=0;char ch=getchar();while (!isdigit(ch)) ch=getchar();while (isdigit(ch)) t=(t<<1)+(t<<3)+ch-48,ch=getchar();return t;
}
void SA(int len,int up)
{int *rk=rank,*t=tmp,d=1,p=0;for (int i=0;i<len;i++) cnt[rk[i]=w[i]]++;for (int i=1;i<up;i++)  cnt[i]+=cnt[i-1];for (int i=len-1;i>=0;i--) sa[--cnt[rk[i]]]=i;for (;;){for (int i=len-d;i<len;i++) id[p++]=i;for (int i=0;i<len;i++)if (sa[i]>=d) id[p++]=sa[i]-d;for (int i=0;i<up;i++) cnt[i]=0;for (int i=0;i<len;i++) cnt[t[i]=rk[id[i]]]++;for (int i=1;i<up;i++) cnt[i]+=cnt[i-1];for (int i=len-1;i>=0;i--) sa[--cnt[t[i]]]=id[i];swap(t,rk);rk[sa[0]]=0;p=1;for (int i=0;i<len-1;i++)if (sa[i]+d<len&&sa[i+1]+d<len&&t[sa[i]]==t[sa[i+1]]&&t[sa[i]+d]==t[sa[i+1]+d])rk[sa[i+1]]=p-1; elserk[sa[i+1]]=p++;if (p==len) return;d<<=1;up=p;p=0;}
}
void Height(int len)
{for (int i=1;i<=len;i++) rank[sa[i]]=i;int x,k=0;for (int i=0;i<len;i++){k=max(0,k-1);x=sa[rank[i]-1];while (w[x+k]==w[i+k]) k++;height[rank[i]]=k;}
}
int LCP(int a,int b)
{if (a==b) return n-sa[a];if (a>b) swap(a,b);int t=log2(b-a);return min(f[a+1][t],f[b+1-(1<<t)][t]);
}
void ct(int x){a[x].siz=a[a[x].ch[0]].siz+a[a[x].ch[1]].siz+1;}
void made(int id,int x){a[id].data=x;a[id].siz=1;}
void rorate(int x,bool mk)
{int y=a[x].fa;a[y].ch[!mk]=a[x].ch[mk];a[a[x].ch[mk]].fa=y;if (a[y].fa){if (a[a[y].fa].ch[0]==y) a[a[y].fa].ch[0]=x;else a[a[y].fa].ch[1]=x;}a[x].fa=a[y].fa;a[y].fa=x;a[x].ch[mk]=y;ct(y);ct(x);
}
void splay(int x,int goal)
{int y;while (a[x].fa!=goal){y=a[x].fa;if (a[y].fa==goal){if(a[y].ch[0]==x) rorate(x,1);else rorate(x,0);}else if (a[a[y].fa].ch[0]==y){if (a[y].ch[0]==x) rorate(y,1);else rorate(x,0);rorate(x,1);}else{if (a[y].ch[1]==x) rorate(y,0);else rorate(x,1);rorate(x,0);}}if(!goal) root=x;
}
void insert(int id,int x)
{made(id,x);if (!root) {root=id;return;}int now=root,f=1;while (f){a[now].siz++;if (a[now].data<=x)if (a[now].ch[1]) now=a[now].ch[1];else f=0,a[now].ch[1]=id,a[id].fa=now;elseif (a[now].ch[0]) now=a[now].ch[0];else f=0,a[now].ch[0]=id,a[id].fa=now;}splay(id,0);
}
int find_next_max(int x)
{int now=root,k=0;while (now)if (a[now].data>x)k=(a[k].data>a[now].data||!k)?now:k,now=a[now].ch[0];else now=a[now].ch[1];return k;
}
int find_next_min(int x)
{int now=root,k=0;while (now)if (a[now].data<x)k=(a[k].data<a[now].data||!k)?now:k,now=a[now].ch[1];else now=a[now].ch[0];return k;
}
main()
{n=in();for (int i=0;i<n;i++) b[i].data=in(),b[i].id=i;sort(b,b+n,cmp);w[n-b[0].id-1]=1;int p=2;for (int i=1;i<n;i++)if (b[i].data!=b[i-1].data) w[n-b[i].id-1]=p++;else w[n-b[i].id-1]=p-1;SA(n+1,p);Height(n);for (int i=1;i<=n;i++) f[i][0]=height[i];for (int i=1;i<18;i++)for (int j=1;j<=n-(1<<i-1);j++)f[j][i]=min(f[j][i-1],f[j+(1<<i-1)][i-1]);for (int i=0;i<n;i++){ans+=i+1;int x=find_next_min(rank[n-i-1]),y=find_next_max(rank[n-i-1]);x=a[x].data;y=a[y].data;if (y&&x>=1&&y<=n) ans+=LCP(x,y);if(x>=1) ans-=LCP(x,rank[n-i-1]);if (y&&y<=n) ans-=LCP(rank[n-i-1],y);printf("%lld\n",ans);insert(i+1,rank[n-i-1]);}
}

【BZOJ4516】生成魔咒,后缀数组+Splay相关推荐

  1. 洛谷 P4070 [SDOI2016]生成魔咒 后缀自动机

    题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例如 S=[1, ...

  2. BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]

    4516: [Sdoi2016]生成魔咒 题意:询问一个字符串每个前缀有多少不同的子串 做了一下SDOI2016R1D2,题好水啊随便AK 强行开map上SAM 每个状态的贡献就是\(Max(s)-M ...

  3. BZOJ.4516.[SDOI2016]生成魔咒(后缀自动机 map)

    题目链接 后缀数组做法见这. 直接SAM+map.对于每个节点其产生的不同子串数为len[i]-len[fa[i]]. //15932kb 676ms #include <map> #in ...

  4. bzoj4516 / P4070 [SDOI2016]生成魔咒

    P4070 [SDOI2016]生成魔咒 后缀自动机 每插入一个字符,对答案的贡献为$len[last]-len[fa[last]]$ 插入字符范围过大,所以使用$map$存储. (去掉第35行就是裸 ...

  5. [SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数

    problem luogu-P4070 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1,21,21,2 拼凑起来形成一个魔咒串 [1,2][1,2][1,2]. 一个魔咒串 ...

  6. BZOJ4516: [Sdoi2016]生成魔咒

    BZOJ4516: [Sdoi2016]生成魔咒 Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示. 例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒 ...

  7. P4070 [SDOI2016]生成魔咒(SAM len数组的含义)

    [SDOI2016]生成魔咒 题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1 , 2 1,2 1,2 拼凑起来形成一个魔咒串 [ 1 , 2 ] [1,2] [1, ...

  8. P4070 [SDOI2016]生成魔咒

    P4070 [SDOI2016]生成魔咒 题意: 有n个字符xi,每次在S的末尾加入一个字符,(一开始S为空),每次加入xi后的不相同字串有多少个 题解: 做这个题首先要会后缀数组P3809 [模板] ...

  9. 【ACWing】2572. 生成魔咒

    题目地址: https://www.acwing.com/problem/content/2574/ 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1 , 2 1, 2 1,2 ...

  10. 【SDOI2016】生成魔咒

    Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例 ...

最新文章

  1. 2010中国城市GDP排名
  2. 2020-12-11 Python中的 if __name__ == “__main__“
  3. 【目录】Django-2.0 学习笔记
  4. 多个ai文件合并成pdf_如何将多个文档合并成PDF?
  5. Docker命令行探秘
  6. FTOUR2 - Free tour II
  7. python泊松_Poisson Distribution——泊松分布
  8. 别催了,医药行业数字化转型真的“急不得”
  9. Msm8960(APQ8064)平台的MSM-AOSP-kitkat编译适配(9):摄像头GPS传感器
  10. 网站备案必须有服务器吗,域名备案必须有服务器吗
  11. 计算机组成原理复习大纲
  12. chrome用 --proxy-server 单独设置代理
  13. mysql where id_MySQL where 子句
  14. 日期时间存入数据库会差一天?
  15. Supervised Contrastive Learning For Recommendation
  16. C Primer Plus编程题-第五章 运算符、表达式和语句
  17. 该shi的垃圾短信,为何屡禁不止?有何猫腻?
  18. uniapp开发写了key 但微信小程序时警告-Now you can provide attr `wx:key` for a `wx:for` to improve performance.
  19. 2021年有哪些能用的活体人物虚拟主播
  20. DI(Dependence Injection)依赖注入

热门文章

  1. 使用ModelArts自动学习完成猫狗声音分类
  2. 【深入浅出etcd系列】1. 架构概览
  3. 风变python小课离线版_Python是个什么鬼?为什么医学生朋友圈里都是它!
  4. 无线打印 airprint 服务器,Docker容器实现Airprint 打印服务器功能
  5. Think in Java第四版 读书笔记2
  6. php中用js自定义弹窗,用js实现的自定义的对话框的实现代码_javascript技巧
  7. HTTP基础--chapter2结束了
  8. IPython高级用法(一)定制命令别名及存储别名
  9. 基于C语言、线性表的 二、八、十、十六进制转换 及 加运算、左右移位运算、乘法运算 的科学计算器设计
  10. 一、Linear Regression