一开始的时候感觉就是一个主席树裸题。

然后发现自己错了。

首先建出后缀数组。

设\(i<j\)

如果\(rk[i]>rk[j]\)显然i更优。

如果\(rk[i]<rk[j]\)不一定是j更优。

当\(i+lcp(i,j)-1<=j\)时是\(j\)优,否则\(i\)更优。

所以我们有一个初步的想法。离线之后把询问按右端点从小到大排序。

然后我们从1到n枚举,用平衡树维护当前可能的答案。

然后当平衡树某一个点\(i\)满足\(rk[i]<rk[j]\)且\(i+lcp(i,j)-1<=j\)时就把\(i\)从平衡树中删去。

询问时\(l\)的后继就是答案。

从这里就可以看出答案是成区间分布的。我们只需要关心什么时候当前最优的答案会改变。

具体的话我们可以维护一个递减的单调栈。当插入一个数时,把小于这个数rk的数弹出,并给弹出的数附一个从平衡树中删除的位置\(i+lcp(rk[stack[top]],rk[i])\),并把i插入平衡树。当扫到这个点的时候把对应的数从平衡树中删掉就行了。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<ctime>
using namespace std;
const int N=101000;
vector<int> vec[N];
char s[N];
int c[N],x[N],n,m,y[N],sa[N],rk[N],height[N];
int mn[N][20];
int tot,rad[N],w[N],v[N],ch[N][2],root,X,Y,Z;
int top,stack[N],ans[N];
struct ques{
int l,r,id;
}q[N];
bool cmp(ques a,ques b){
return a.r<b.r;
}
void get_sa(){
for(int i=1;i<=n;i++)c[x[i]=s[i]]++;
for(int i=1;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int num=0;
for(int i=n-k+1;i<=n;i++)y[++num]=i;
for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
for(int i=1;i<=m;i++)c[i]=0;
for(int i=1;i<=n;i++)c[x[i]]++;
for(int i=1;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
for(int i=1;i<=n;i++)swap(x[i],y[i]);
x[sa[1]]=1;num=1;
for(int i=2;i<=n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
if(n==num)break;
m=num;
}
}
void get_height(){
int k=0;
for(int i=1;i<=n;i++)rk[sa[i]]=i;
for(int i=1;i<=n;i++){
if(rk[i]==1)continue;
if(k)k--;
int j=sa[rk[i]-1];
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
height[rk[i]]=k;
}
}
void pre_work(){
for(int i=1;i<=n;i++)mn[i][0]=height[i];
int len=log2(n);
for(int j=1;j<=len;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]);
}
int lcp(int l,int r){
if(l>r)swap(l,r);
l++;
int len=log2(r-l+1);
return min(mn[l][len],mn[r-(1<<len)+1][len]);
}
int new_node(int a,int b){
int now=++tot;
rad[now]=rand();v[now]=a;w[now]=b;
return now;
}
int merge(int x,int y){
if(!x||!y)return x+y;
if(rad[x]>rad[y]){
ch[x][1]=merge(ch[x][1],y);
return x;
}
else{
ch[y][0]=merge(x,ch[y][0]);
return y;
}
}
void split(int &x,int &y,int now,int k){
if(now==0)x=y=0;
else{
if(v[now]<=k){
x=now;
split(ch[x][1],y,ch[x][1],k);
}
else{
y=now;
split(x,ch[y][0],ch[y][0],k);
}
}
}
int kth(int now,int k){
if(ch[now][0])return kth(ch[now][0],k);
return now;
}
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum*f;
}
int main(){
srand(time(NULL));
scanf("%s",s+1);
n=strlen(s+1);
m=2000;
get_sa();
get_height();
pre_work();
m=read();
for(int i=1;i<=m;i++)
q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+1+m,cmp);
int now=1;
for(int i=1;i<=n;i++){
while(top&&rk[stack[top]]<rk[i])vec[i+lcp(rk[stack[top]],rk[i])].push_back(stack[top]),top--;
stack[++top]=i;
split(X,Y,root,i);
root=merge(merge(X,new_node(i,rk[i])),Y);
for(int j=0;j<vec[i].size();j++){
split(X,Z,root,vec[i][j]);
split(X,Y,X,vec[i][j]-1);
root=merge(X,Z);
}
while(q[now].r==i){
split(X,Y,root,q[now].l-1);
ans[q[now].id]=v[kth(Y,1)];
root=merge(X,Y);
now++;
}
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}

BZOJ 4453 cys就是要拿英魂!(后缀数组+单调栈+平衡树)的更多相关文章

  1. BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)

    BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...

  2. 【BZOJ-3238】差异 后缀数组 + 单调栈

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1561  Solved: 734[Submit][Status] ...

  3. BZOJ_3879_SvT_后缀数组+单调栈

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

  4. BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈

    BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...

  5. 【BZOJ3879】SvT 后缀数组+单调栈

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

  6. BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】

    题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...

  7. BZOJ 4453: cys就是要拿英魂![后缀数组 ST表 单调栈类似物]

    4453: cys就是要拿英魂! Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 90  Solved: 46[Submit][Status][Discu ...

  8. BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】

    题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...

  9. BZOJ.4453.cys就是要拿英魂!(后缀数组 单调栈)

    BZOJ 求字典序最大,容易想到对原串建后缀数组求\(rk\). 假设当前区间是\([l,r]\),对于在\([l,r]\)中的两个后缀\(i,j\)(\(i<j\)),显然我们不能直接比较\( ...

随机推荐

  1. Core Graphics框架 利用Quartz 2D绘图

    首先,什么是Core Graphics和Quartz 2D? Core Graphics:是基于Quartz 2D绘图引擎的一个C语言的API绘图框架.它也是iOS开发中最基本的框架(Framewor ...

  2. ABBYY简体中文版终身授权半价来袭,真的是5折!

    经过了一个春秋,心心念念的双十一终于要来了,一年时间并不长,但这一个月尤其慢!ABBYY官方称为回馈广大用户的支持与厚爱,双十一期间,ABBYY价格感人,诱惑难挡. 说到双十一活动,方式也是五花八门, ...

  3. Pyhton学习——Day33

    #并发式编程# 操作系统是一个用来协调.管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用程序之间.# (程序是运行在系统上的具有某种功能的软件,比如说浏览器,音乐播放器等.)# 操作系统的内 ...

  4. python 用法测试

    Python 3.5.6 1.js风格的回调测试 def b(): ') def a(fn): if callable(fn): fn() a(b) class Sample: def q(self) ...

  5. js正则表达式注册页面表单验证

    可以这样校验 <html> <head> <meta http-equiv="Content-Type" content="text/htm ...

  6. keepalived 和 heartbeat对比

    Keepalived使用的vrrp协议方式,虚拟路由冗余协议 (Virtual Router Redundancy Protocol,简称VRRP): Heartbeat是基于主机或网络的服务的高可用 ...

  7. FROM使用子查询

    FROM使用子查询    子查询结果充当一个临时表.    //子查询形成的临时表字段为NO,NAME,SAL   select no,name from(     select empno no,e ...

  8. 51 nod 1431 快乐排队

    1431 快乐排队 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题  收藏  关注 有一群人在排队,如果某个人想排到前面去,可以花 ...

  9. pip安装-mac电脑

    If you meant "pip" specifically: Homebrew provides pip via: `brew install python`. However ...

  10. HDU 4310 Contest 2

    贪心,注意排序条件. #include <iostream> #include <cstdio> #include <algorithm> using namesp ...