SvT bzoj-3879

题目大意:给定一个字符串。每次询问给定$t$个位置,求两两位置开头的后缀的$LCP$之和。

注释:$1\le length\le 5\cdot 10^5$,$\sum t\le 3\cdot 10^6$。


想法

不难想到构建后缀数组。

进而我们的问题就转化成了给定序列上一些位置求这些位置两两之间区间最小值的和。

对$ht$数组建立$ST$表。

接下来的过程可以用单调栈维护。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 500010
using namespace std; typedef long long ll;
int n,m,wa[N],wb[N],wv[N],sa[N],height[N],rank[N],r[N],Ws[N];
char ch[N];
int f[21][N],L[N],vis[N],s[N],g[N];
int v[3000050],Q[3000050];
ll dp[N];
inline char nc()
{
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd()
{
int x=0; char c=nc();
while(c<'0'||c>'9') c=nc();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=nc();
return x;
}
inline int rc()
{
char c=nc();
while(c<'a'||c>'z') c=nc();
return (int)c;
} void build_sa()
{
m=27;
int i,j,p,*x=wa,*y=wb,*t;
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(p=j=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 get_min(int l,int r)
{
int len=L[r-l+1];
return min(f[len][l],f[len][r-(1<<len)+1]);
}
void ST()
{
int i,j;
for(i=2;i<=n;i++) L[i]=L[i>>1]+1;
for(i=1;i<=n;i++) f[0][i]=height[i];
for(i=1;(1<<i)<=n;i++)
{
for(j=1;j+(1<<i)-1<=n;j++) f[i][j]=min(f[i-1][j],f[i-1][j+(1<<(i-1))]);
}
}
bool cmp(int x,int y)
{
return rank[x]<rank[y];
}
int main()
{
int T;
n=rd(); T=rd();
int i;
for(i=0;i<n;i++) r[i]=rc()-'a'+1;
r[n++]=0;
int tot=0;
build_sa(); n--; ST();
while(T--)
{
tot++;
int t=0;
v[0]=rd();
int j;
for(j=1;j<=v[0];j++)
{
v[j]=rd();
v[j]--;
if(vis[v[j]]==tot) {j--; v[0]--;}
vis[v[j]]=tot;
}
sort(v+1,v+v[0]+1,cmp);
for(j=1;j<v[0];j++)
{
g[j]=get_min(rank[v[j]]+1,rank[v[j+1]]);
}
t=1; Q[1]=0;
long long ans=0;
for(j=1;j<v[0];j++)
{
while(t&&g[Q[t]]>g[j]) t--;
dp[j]=dp[Q[t]]+1ll*(j-Q[t])*g[j];
ans+=dp[j];
Q[++t]=j;
}
printf("%lld\n",ans);
}
return 0;
}

小结:后缀数组真好玩。

[bzoj3879]SvT_后缀数组_RMQ_单调栈的更多相关文章

  1. poj3415 Common Substrings(后缀数组,单调栈 | 后缀自动机)

    [题目链接] http://poj.org/problem?id=3415 [题意] A与B长度至少为k的公共子串个数. [思路] 基本思想是将AB各个后缀的lcp-k+1的值求和.首先将两个字符串拼 ...

  2. [bzoj3238][Ahoi2013]差异_后缀数组_单调栈

    差异 bzoj-3238 Ahoi-2013 题目大意:求任意两个后缀之间的$LCP$的和. 注释:$1\le length \le 5\cdot 10^5$. 想法: 两个后缀之间的$LCP$和显然 ...

  3. 洛谷P2178 [NOI2015]品酒大会 后缀数组+单调栈

    P2178 [NOI2015]品酒大会 题目链接 https://www.luogu.org/problemnew/show/P2178 题目描述 一年一度的"幻影阁夏日品酒大会" ...

  4. Gym - 102028H Can You Solve the Harder Problem? (后缀数组+RMQ+单调栈)

    题意:求一个序列中本质不同的连续子序列的最大值之和. 由于要求“本质不同”,所以后缀数组就派上用场了,可以从小到大枚举每个后缀,对于每个sa[i],从sa[i]+ht[i]开始枚举(ht[0]=0), ...

  5. 洛谷4248 AHOI2013差异 (后缀数组SA+单调栈)

    补博客! 首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); ...

  6. 【POJ3415】Common Substrings(后缀数组,单调栈)

    题意: n<=1e5 思路: 我的做法和题解有些不同 题解是维护A的单调栈算B的贡献,反过来再做一次 我是去掉起始位置不同这个限制条件先算总方案数,再把两个串内部不合法的方案数减去 式子展开之后 ...

  7. 【BZOJ3238】差异(后缀数组,单调栈)

    题意: 思路:显然len(t[i])+len(t[j])这部分的和是一定的 那么问题就在于如何快速求出两两之间lcp之和 考虑将它们排名后用SA可以很方便的求出lcp,且对答案没有影响,因为形式都是数 ...

  8. POJ.3145.Common Substrings(后缀数组 倍增 单调栈)

    题目链接 \(Description\) 求两个字符串长度不小于k的公共子串对数. \(Solution\) 求出ht[]后先减去k,这样对于两个后缀A',B',它们之间的贡献为min{ht(A)}( ...

  9. BZOJ3879:SvT(后缀数组,单调栈,ST表)

    Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始 ...

随机推荐

  1. Oracle Mysql的jdbc连接

    Oracle和MySql的jdbc或连接池中的连接,写下来以便随时参考 Oracle: driverClassName=oracle.jdbc.driver.OracleDriver url=jdbc ...

  2. Common.Logging.dll----------配置方式,可选引用,用于日志输出

    1.简介common logging是一个通用日志接口,log4net是一个具体实现. common logging可以把输出连接到其他非log类上, 如EntLib的日志.NLog等 2.使用接下来 ...

  3. QQ感叹号是什么鬼?原来是服务器波动,腾讯官方来辟谣了

    今天晚上很多网友在用QQ发送消息的时候发现,自己发送的消息一直是感叹号❗到底是怎么回事呢?是消息都发不出去了吗?马浩周通过手机测试后发现,其实消息是可以发出去的,而官方手机QQ出来已经通知了,是服务器 ...

  4. swift class extension 与继承

    1.扩展中无法继承重写已有函数,不能添加函数. Extensions can add new functionality to a type, but they cannot override exi ...

  5. call, apply, bind 区别

    #call, apply, bind 区别及模拟实现call apply bind 三者都可以用来改变this的指向,但是在用法上略有不同  首先说一下call和apply的区别 call和apply ...

  6. No-7.运算符

    数学符号表链接:https://zh.wikipedia.org/wiki/数学符号表 01. 算数运算符 是完成基本的算术运算使用的符号,用来处理四则运算 运算符 描述 实例 + 加 10 + 20 ...

  7. hdfs深入:02、今日课程内容大纲以及hdfs的基本实现

    1.hadoop第三天课程内容 hdfs:分布式文件存储系统hdfs的架构图hdfs的副本机制以及block块hdfs的元数据信息fsimage与editshdfs的文件读写过程hdfs的javaAP ...

  8. bootstrap-table的一些基本使用及表内编辑的实现

    最近工作需要接触了bootstrap-table 所以研究了一下,并做了笔记,红色位置要特别注意 前端主要使用了 jquery bootstrap-table  bootstrap-edittable ...

  9. python中的next()以及iter()函数

    我们首先要知道什么是可迭代的对象(可以用for循环的对象)Iterable: 一类:list,tuple,dict,set,str 二类:generator,包含生成器和带yield的generato ...

  10. Bullet:MySQL增强半同步参数rpl_semi_sync_master_wait_point值AFTER_SYNC和AFTER_COMMIT的对比实验

    MySQL 5.7.22启用增强半同步复制 MySQL对该参数值的描述 Semisync can wait for slave ACKs at one of two points, AFTER_SYN ...