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 方法重写原则
方法重写应遵循“三同一小一大”原则: “三同”:即方法名相同,形参列表相同,返回值类型相同: “一小”:子类方法声明抛出的异常比父类方法声明抛出的异常更小或者相等: “一大”:子类方法的访问修饰符应比 ...
- DataView中的 Sort 排序
using System.Data; using System; public class A { static void Main(string[] args) { DataTable locati ...
- com.opensymphony.xwork2.ognl.OgnlValueStack - Error setting expression 'customer.applyRate' with value '[Ljava.lang.String;@7d3fae2c'
出错的3个最可能的原因:我是第二种错误 1.action配置错误 <action name="doCreateMeetingInfo" class="meeting ...
- c# mvc 路由规则学习片段
1.初步接触mvc 路由 routes.MapRoute( "CM", "CM/{controller}/{act ...
- 进程间的八种通信方式----共享内存是最快的 IPC 方式
1.无名管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. 2.高级管道(popen):将另一个程序当做一个新 ...
- Android-Android Studio 3.0找不到Android Device Monitor
原文:https://blog.csdn.net/yuanxiang01/article/details/80494842?utm_source=copy 为什么Android Studio 3. ...
- Android_YouthArea之ApeendTextView
这次给我自己的项目打个广告:http://sj.qq.com/myapp/detail.htm?apkName=com.youthcommunity 这款APP 不同于SoHOT是积极的,是年轻人的信 ...
- 多文档自己主动文摘:Multi-Document Summarization,MDS
- EasyPlayerPro Windows播放器进行本地对讲喊话音频采集功能实现
需求 在安防行业应用中,除了在本地看到摄像机的视频和进行音频监听外,还有一个重要的功能,那就是对讲. EasyPlayerPro-win为了减轻二次开发者的工作量,将本地音频采集也进行了集成: 功能特 ...
- 用Darwin和live555实现的直播框架
我们在开发视频直播或者监控类项目的时候,如场馆监控.学校监控.车载监控等等,往往首先希望的是形成一个项目的雏形,然后再在这个框架的基础上进行不断的完善和扩展工作,那么我们今天要给大家介绍的就是,如何形 ...