bzoj 4453 cys就是要拿英魂! —— 后缀数组+单调栈+set
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4453
这种问题...一般先把询问离线,排序;
区间对后缀排名的影响在于一些排名大而位置靠后的后缀可能因为区间右端点截掉了后面而排名变小;
考虑如何影响:如果 i < j
rk[i] > rk[j] ,那么字典序 i 一直大于 j
rk[i] < rk[j] ,那么如果右端点 R <= j + LCP(i,j),字典序 i > j,如果 R > j + LCP(i,j),字典序 i < j
而如果对询问区间按右端点排序,右端点就是递增的;
需要处理一下 i < j , rk[i] < rk[j] 的情况,由于每个 i 只考虑暂时大于它后面第一个 j (若还有 k,之后考虑 j 暂时大于 k),所以用单调栈找到后面第一个大于的;
有类似插入、删除这样的操作,可以用 set 维护,当 R > j + LCP 后,就把 i 删除;
令 set 里面是当前有贡献的位置,也就是单调栈里的位置和虽然被弹出但暂时大于后面某个后缀的位置;
然后在位置上开个 vector 记录到这个地方贡献就失效的后缀,到了后把它们再从 set 里删除;
因为 set 里位置的贡献也是从左到右单调递减的,那么每次取 L 右边第一个就是答案;
别写错ST表!
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#define pb push_back
using namespace std;
int const xn=1e5+;
int n,m,tax[xn],tp[xn],sa[xn],rk[xn],sta[xn],top,dc[xn],ht[xn][],bin[],r[xn],ans[xn];
char s[xn];
vector<int>v[xn],com[xn];
set<int>st;
set<int>::iterator it;
struct N{int l,r,id;}q[xn];
bool cmp(N x,N y){return x.r<y.r;}
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return f?ret:-ret;
}
void Rsort()
{
for(int i=;i<=m;i++)tax[i]=;
for(int i=;i<=n;i++)tax[rk[tp[i]]]++;
for(int i=;i<=m;i++)tax[i]+=tax[i-];
for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
}
void work()
{
for(int i=;i<=n;i++)rk[i]=s[i],tp[i]=i;
Rsort();
for(int k=;k<=n;k<<=)
{
int num=;
for(int i=n-k+;i<=n;i++)tp[++num]=i;
for(int i=;i<=n;i++)
if(sa[i]>k)tp[++num]=sa[i]-k;
Rsort(); swap(rk,tp);
rk[sa[]]=; num=;
for(int i=;i<=n;i++)
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[sa[i]+k]==tp[sa[i-]+k])?num:++num;
if(num==n)break;
m=num;
}
}
void get()
{
int k=;
for(int i=;i<=n;i++)
{
if(rk[i]==)continue;
if(k)k--; int j=sa[rk[i]-];
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
ht[rk[i]][]=k;
}
bin[]=; for(int i=;i<;i++)bin[i]=(bin[i-]<<);
r[]=; for(int i=;i<=n;i++)r[i]=r[i>>]+;
for(int j=;j<;j++)
for(int i=;i<=n&&i+bin[j]-<=n;i++)
ht[i][j]=min(ht[i][j-],ht[i+bin[j-]][j-]);//
}
int getlcp(int x,int y)
{
if(x==y)return n;
x=rk[x]; y=rk[y];
if(x>y)swap(x,y); x++;
int w=r[y-x+];
return min(ht[x][w],ht[y-bin[w]+][w]);//
}
int main()
{
scanf("%s",s+); n=strlen(s+);
for(int i=;i<=n;i++)dc[i]=(int)s[i];
sort(dc+,dc+n+); m=unique(dc+,dc+n+)-dc-;
for(int i=;i<=n;i++)s[i]=lower_bound(dc+,dc+m+,(int)s[i])-dc;
work(); get();
int Q=rd();
for(int i=;i<=Q;i++)q[i].l=rd(),q[i].r=rd(),q[i].id=i;
sort(q+,q+Q+,cmp); int p=;
for(int i=;i<=Q;i++)
{
while(p<q[i].r)
{
p++; int y;
while(rk[y=sta[top]]<rk[p]&&top)//<
{
int pos=min(n+,p+getlcp(y,p));
v[pos].pb(y); com[p].pb(y);
top--;
}
sta[++top]=p; st.insert(p);
for(int i=,x;i<v[p].size();i++)
if(st.count(x=v[p][i]))
{
for(int j=;j<com[x].size();j++)
if(st.count(com[x][j]))st.erase(com[x][j]);
st.erase(x);
}
}
it=st.lower_bound(q[i].l);
ans[q[i].id]=*it;
}
for(int i=;i<=Q;i++)printf("%d\n",ans[i]);
return ;
}
bzoj 4453 cys就是要拿英魂! —— 后缀数组+单调栈+set的更多相关文章
- BZOJ.4199.[NOI2015]品酒大会(后缀数组 单调栈)
BZOJ 洛谷 后缀自动机做法. 洛谷上SAM比SA慢...BZOJ SAM却能快近一倍... 显然只需要考虑极长的相同子串的贡献,然后求后缀和/后缀\(\max\)就可以了. 对于相同子串,我们能想 ...
- 【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]. 现在有若干组询问,对于每一个 ...
- BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈
BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...
- 【BZOJ3879】SvT 后缀数组+单调栈
[BZOJ3879]SvT Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干 ...
- BZOJ3238 [Ahoi2013]差异 【后缀数组 + 单调栈】
题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...
- BZOJ 4453: cys就是要拿英魂![后缀数组 ST表 单调栈类似物]
4453: cys就是要拿英魂! Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 90 Solved: 46[Submit][Status][Discu ...
- BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】
题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...
- BZOJ.4453.cys就是要拿英魂!(后缀数组 单调栈)
BZOJ 求字典序最大,容易想到对原串建后缀数组求\(rk\). 假设当前区间是\([l,r]\),对于在\([l,r]\)中的两个后缀\(i,j\)(\(i<j\)),显然我们不能直接比较\( ...
随机推荐
- java nio读取和写入文件
读取 package com.test; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputS ...
- java 匿名类和匿名方法
package com.test; interface product{ int getPrice(); } public class News { /** * @param args */ publ ...
- java操作pdf
使用pdf模板生成pdf 1,工具 Adobe Acrobat X Pro 2,pom文件配置 <dependency> <groupId>com.itextpdf</g ...
- HDFS源码分析数据块复制监控线程ReplicationMonitor(一)
ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列.其定义及作为线程核心的run()方法如下: ...
- 【BZOJ2789】[Poi2012]Letters 树状数组
[BZOJ2789][Poi2012]Letters Description 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符 ...
- 【BZOJ4435】[Cerc2015]Juice Junctions Tarjan+hash
[BZOJ4435][Cerc2015]Juice Junctions Description 你被雇佣升级一个旧果汁加工厂的橙汁运输系统.系统有管道和节点构成.每条管道都是双向的,且每条管道的流量都 ...
- 记录日志(Log4Net)
一:Log4net的简单示例 1.新建控制台应用程序,右键属性,把其框架.NET Framework4 Client Profile 修改为.NET Framework4,此时项目中将会自动添加一个A ...
- 九度OJ 1005:Graduate Admission (排序)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5646 解决:1632 题目描述: It is said that in 2011, there are about 100 graduat ...
- wepy 实现 用户名登录与短信验证码登录
wepy 实现 用户名登录与短信验证码登录
- 【题解】P4799[CEOI2015 Day2]世界冰球锦标赛
[题解][P4799 CEOI2015 Day2]世界冰球锦标赛 发现买票顺序和答案无关,又发现\(n\le40\),又发现从后面往前面买可以通过\(M\)来和从前面往后面买的方案进行联系.可以知道是 ...