BZOJ3879:SvT(后缀数组,单调栈,ST表)
Description
(我并不想告诉你题目名字是什么鬼)
有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].
现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.
Input
第一行两个正整数n,m,分别表示S的长度以及询问的次数.
接下来一行有一个字符串S.
接下来有m组询问,对于每一组询问,均按照以下格式在一行内给出:
首先是一个整数t,表示共有多少个后缀.接下来t个整数分别表示t个后缀在字符串S中的出现位置.
Output
Sample Input
popoqqq
1 4
2 3 5
4 1 2 5 6
Sample Output
0
2
Hint
样例解释:
对于询问一,只有一个后缀”oqqq”,因此答案为0.
对于询问二,有两个后缀”poqqq”以及”qqq”,两个后缀之间的LCP为0,因此答案为0.
对于询问三,有四个后缀”popoqqq”,”opoqqq”,”qqq”,”qq”,其中只有”qqq”,”qq”两个后缀之间的LCP不为0,且长度为2,因此答案为2.
对于100%的测试数据,有S<=5*10^5,且Σt<=3*10^6.
特别注意:由于另一世界线的某些参数发生了变化,对于一组询问,即使一个后缀出现了多次,也仅算一次.
Solution
首先把所有后缀按照$Rank$排序,然后用$ST$表求出相邻的$lcp$。
现在问题变成了对于一个序列的所有区间$(x,y)$,求出每个区间内的最小值的和。
逆向思维一下,考虑每个值可以作为最小值在哪些区间内出现,
也就是对每一个数求左边第一个小于等于它的数和右边第一个小于它的数,这个可以用单调栈维护。
$vector$去重的时候不能

必须

Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#define N (500009)
#define LL long long
#define MOD (23333333333333333LL)
using namespace std; int n,m=,q,t,L[N],R[N],stack[N],top;
int wt[N],wa[N],wb[N];
int SA[N],Rank[N],Height[N];
int LOG2[N],ST[N][];
char r[N];
vector<int>v,w; inline int read()
{
int x=,w=; char c=getchar();
while (c<'' || c>'') {if (c=='-') w=-; c=getchar();}
while (c>='' && c<='') x=x*+c-'', c=getchar();
return x*w;
} bool cmp(int *y,int a,int b,int k)
{
int arank1=y[a];
int brank1=y[b];
int arank2=a+k>=n?-:y[a+k];
int brank2=b+k>=n?-:y[b+k];
return arank1==brank1 && arank2==brank2;
} void Build_SA()
{
int *x=wa,*y=wb;
for (int i=; i<m; ++i) wt[i]=;
for (int i=; i<n; ++i) wt[x[i]=r[i]]++;
for (int i=; i<m; ++i) wt[i]+=wt[i-];
for (int i=n-; i>=; --i) SA[--wt[x[i]]]=i; for (int j=; j<=n; j<<=)
{
int p=;
for (int i=n-j; i<n; ++i) y[p++]=i;
for (int i=; i<n; ++i) if (SA[i]>=j) y[p++]=SA[i]-j; for (int i=; i<m; ++i) wt[i]=;
for (int i=; i<n; ++i) wt[x[y[i]]]++;
for (int i=; i<m; ++i) wt[i]+=wt[i-];
for (int i=n-; i>=; --i) SA[--wt[x[y[i]]]]=y[i]; m=; swap(x,y);
x[SA[]]=;
for (int i=; i<n; ++i)
x[SA[i]]=cmp(y,SA[i],SA[i-],j)?m-:m++;
if (m>=n) break;
}
} void Build_Height()
{
for (int i=; i<n; ++i) Rank[SA[i]]=i;
int k=; Height[]=;
for (int i=; i<n; ++i)
{
if (!Rank[i]) continue;
if (k) k--;
int j=SA[Rank[i]-];
while (r[i+k]==r[j+k]) k++;
Height[Rank[i]]=k;
}
} void Build_ST()
{
int t=;
for(int i=;i<=n;i++) LOG2[i]=LOG2[i>>]+;
for (int i=; i<n; ++i) ST[i][]=Height[i];
for (int j=; j<=; ++j)
for (int i=; i+(<<j)-<n; ++i)
ST[i][j]=min(ST[i][j-],ST[i+(<<j-)][j-]);
} int Query(int l,int r)
{
int k=LOG2[r-l+];
return min(ST[l][k],ST[r-(<<k)+][k]);
} bool cmp1(int a,int b)
{
return Rank[a]<Rank[b];
} int main()
{
n=read(); q=read(); scanf("%s",r);
Build_SA(); Build_Height(); Build_ST();
while (q--)
{
v.clear(); w.clear();
t=read();
for (int i=; i<=t; ++i) v.push_back(read()-);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()), v.end());
sort(v.begin(),v.end(),cmp1);
w.push_back(-);
for (int i=; i<v.size(); ++i)
w.push_back(Query(Rank[v[i-]]+,Rank[v[i]]));
w.push_back(-);
int ws=w.size();
stack[top=]=;
for (int i=; i<ws-; ++i)
{
while (top && w[stack[top]]>w[i]) top--;
L[i]=stack[top]; stack[++top]=i;
}
stack[top=]=ws-;
for (int i=ws-; i>=; --i)
{
while (top && w[stack[top]]>=w[i]) top--;
R[i]=stack[top]; stack[++top]=i;
}
LL ans=;
for (int i=; i<ws-; ++i) (ans+=1ll*(i-L[i])*(R[i]-i)%MOD*w[i]%MOD)%MOD;
printf("%lld\n",ans);
}
}
BZOJ3879:SvT(后缀数组,单调栈,ST表)的更多相关文章
- BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】
题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...
- 【BZOJ3879】SvT 后缀数组+单调栈
[BZOJ3879]SvT Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干 ...
- 【BZOJ-3238】差异 后缀数组 + 单调栈
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1561 Solved: 734[Submit][Status] ...
- BZOJ_3879_SvT_后缀数组+单调栈
BZOJ_3879_SvT_后缀数组+单调栈 Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个 ...
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...
- BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈
BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
- BZOJ3879: SvT【后缀数组+单调栈】
Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始 ...
- [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】
题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么 ...
随机推荐
- SQL语句大全从基础到熟练(不含数据库高端操作)日常用户 三、
前言 昨天晚上回家忘记带钥匙导致在楼下站街三小时,鬼天气热的不要不要的然后我就在车里坐了会之后就.....zzZZ,哈哈睡的挺香的毕竟累了一天了 上两篇文章都是介绍的语法语句,本篇文章介绍下函数的使用 ...
- c#数据库设计--1、概述
一.数据库设计的概念 数据库设计是将数据库中的数据实体及这些数据实体之间的关系,进行规划和结构化的过程. 二.数据库设计的重要性 设计决定代码量,一将不行,累死三军. 如果一个数据库没有进行一个良好的 ...
- 比较全git的.ignore文件配置
# maven,gradle ignoretarget/_build/build/_site/.gradle*dependency-reduced-pom.xmltest.* # eclipse ig ...
- 3.Decorator Pattern(装饰者模式)
装饰者模式: 动态地将责任附加到对象上.想要扩展功能,装饰者提供有别于继承的另一种选择. 举例: 不知道大家学校的食堂是什么点餐制度(或者大家就直接想成吃火锅,我们要火锅料 + 配菜),我们学校的点餐 ...
- HDU6188
Duizi and Shunzi Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- BOM(JavaScript高程笔记)
再次编辑于20160115 一.window对象 双重角色 JS访问浏览器窗口的接口 ECAMAscript规定的Global对象 1.全局作用域 所有在全局作用域中声明的变量.函数都会变成windo ...
- BZOJ3351: [ioi2009]Regions(根号分治)
题意 题目链接 Sol 很神仙的题 我们考虑询问(a, b)(a是b的祖先),直接对b根号分治 如果b的出现次数\(< \sqrt{n}\),我们可以直接对每个b记录下与它有关的询问,这样每个询 ...
- js-ES6学习笔记-for...of循环
1.一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for...of循环遍历它的成员.也就是说,for...of循环内部调用的是数据结构的Symbo ...
- BFC(块状格式化上下文)
今天先来说关于BFC的一些基础知识 BFC是块状格式化上下文,它是一个独立的渲染区域,规定了内部如何布局,并且这个布局和外部毫不相干 触发BFC的方法 1.根元素(即html) 2.float属性不为 ...
- 【代码笔记】iOS-自定义loading
一,效果图. 二,工程图. 三, 代码. ViewController.h #import <UIKit/UIKit.h> //loading #import "GPLoadin ...