题目: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 ;
}

最新文章

  1. 连载《一个程序猿的生命周期》-6、自学C++,二级考过后,为工作的机会打下了基础
  2. [原] XAF 如何非常容易禁止清除一个下拉字段的值?
  3. JavaScript + HTML DOM (keep for myself)
  4. Vim 新用法
  5. Vector示例一,二
  6. Java8 map和reduce
  7. DSO分类及应用
  8. LeetCode &amp; Q169-Majority Element-Easy
  9. 关系型数据库 VS 非关系型数据库
  10. CF1152E Neko and Flashback--欧拉路径
  11. oracle sql语句实现累加、累减、累乘、累除
  12. Silverlight实用窍门系列:68.Silverlight的资源字典ResourceDictionary
  13. OpenTSDB安装
  14. 【384】reduce归纳、map映射、filter筛选 的用法
  15. linux执行jmeter脚本报错
  16. 消除JQuery Mobile 列表样式右侧箭头
  17. Html基本操作实例代码
  18. mt7620 wireless驱动特性意外发现
  19. 新浪通过API分享 实践
  20. Java中权限设置

热门文章

  1. ExtJs4学习(二):Dom操作
  2. Two stage U-Boot design
  3. 做一个合格的程序员之浅析Spring AOP源代码(十八) Spring AOP开发大作战源代码解析
  4. linux 打印系统时间操作
  5. python中装饰器你真的理解吗?
  6. 使用OpenSessionInViewFilter的注意事项
  7. adaptive heuristic critic 自适应启发评价 强化学习
  8. php函数: set_error_handler
  9. 详解Vue 实例中的生命周期钩子
  10. mybatis 运算符转义收录