题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4453

询问离线,按R排序。

发现直接用 rk[ ] 的错误情况就是前面的某个位置 j 和自己位置 i 的 LCP 长度大于 i 到当前 R 的长度,这时虽然 rk[ j ] < rk[ i ] ,但答案是 j 。

但是如果 j < i && rk[ j ] > rk[ i ] 的话, j 就总是比 i 优,除非询问的 L 比较靠右。这样有些像单调栈,所以维护一个 rk[ ] 单调递减的单调栈。

这样就要把 j < i && rk[ j ] < rk[ i ] 都弹掉。但是在一定期限内它们也可能是答案。

发现 j < i && rk[ j ] < rk[ i ] 的 j 比 i 优的期限是询问的 R 到 i+LCP( j , i ) 之前。所以把 j 记在 i+LCP( j , i ) 那个位置上,遍历到那个位置的时候就把 j 从答案备选里删去。

要支持这样的删去,考虑用 set 。

发现如果要删去的 j 也有一些 k < j && rk[ k ] < rk[ j ] 的位置 k ,而且此时 k 还没被删去。这样说明 j+LCP( j , k ) > i+LCP( i , j ) ;如果删去 j  ,可以发现 i+LCP( i , k ) 一定等于 i+LCP( i , j ),即这些 k 也应该同时被删去。所以把每个 j 记在 i 上,删去 i 的时候遍历一遍 j 把 j 也删了。

这样的话在位置上遍历要删的东西的时候会发现一些已经被删了。用 bool 数组判断一下就行了。不过自己忘了判断了,竟然也没错。看来如果传进去值的话,也可以删不在 set 里的值?

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int N=1e5+,K=;
int n,m,hd[N],xnt,to[N],nxt[N],phd[N],pnt,pto[N],pxt[N],ans[N];
int sta[N],top,sa[N],rk[N],tp[N],tx[N],ht[N][K],lg[N],bin[K];
char s[N];
struct Node{
int l,r,id;
bool operator< (const Node &b)const
{return r<b.r;}
}t[N];
set<int> st;
int Mn(int a,int b){return a<b?a:b;}
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='') ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
void Rsort(int n,int nm)
{
for(int i=;i<=nm;i++)tx[i]=;
for(int i=;i<=n;i++)tx[rk[i]]++;
for(int i=;i<=nm;i++)tx[i]+=tx[i-];
for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
}
void get_sa(int n)
{
int nm=;
for(int i=;i<=n;i++)tp[i]=i,rk[i]=s[i];
Rsort(n,nm);
for(int k=;k<=n;k<<=)
{
int tot=;
for(int i=n-k+;i<=n;i++)tp[++tot]=i;
for(int i=;i<=n;i++)
if(sa[i]>k)tp[++tot]=sa[i]-k;
Rsort(n,nm);memcpy(tp,rk,sizeof rk);nm=;rk[sa[]]=;
for(int i=,u,v;i<=n;i++)
{
u=sa[i]+k;v=sa[i-]+k;if(u>n)u=;if(v>n)v=;
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[u]==tp[v])?nm:++nm;
}
if(nm==n)break;
}
}
void get_ht(int n)
{
lg[]=;for(int i=;i<=n;i++)lg[i]=lg[i>>]+;
bin[]=;for(int i=;i<=lg[n];i++)bin[i]=bin[i-]<<;
for(int i=,k=,j;i<=n;i++)
{
for(k?k--:,j=sa[rk[i]-];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
ht[rk[i]][]=k;//rk[i]
}
for(int j=;j<=lg[n];j++)
for(int i=;i<=n&&i+bin[j]-<=n;i++)
ht[i][j]=Mn(ht[i][j-],ht[i+bin[j-]][j-]);
}
int get_lcp(int l,int r)
{
if(l==r)return n-l+;
l=rk[l]; r=rk[r]; if(l>r)swap(l,r);
int d=lg[r-l];
return Mn(ht[l+][d],ht[r-bin[d]+][d]);//l+1
}
void add_pos(int x,int y){pto[++pnt]=y;pxt[pnt]=phd[x];phd[x]=pnt;}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void ins(int x){st.insert(x);}
void del(int x){for(int i=hd[x];i;i=nxt[i])st.erase(to[i]);st.erase(x);}
int fnd(int x){return *st.lower_bound(x);}
int main()
{
scanf("%s",s+);n=strlen(s+);get_sa(n);get_ht(n);
m=rdn();
for(int i=;i<=m;i++)t[i].l=rdn(),t[i].r=rdn(),t[i].id=i;
sort(t+,t+m+); int p=;
for(int i=;i<=n;i++)
{
while(top&&rk[sta[top]]<rk[i])
{
int d=get_lcp(sta[top],i);
if(!d){del(sta[top]);top--;continue;}
add_pos(i+d,sta[top]); //not -1
add(i,sta[top]);top--; //i to sta[top]
}
sta[++top]=i;ins(i);
for(int j=phd[i];j;j=pxt[j])del(pto[j]);
for(;p<=m&&t[p].r==i;p++)
ans[t[p].id]=fnd(t[p].l);
}
for(int i=;i<=m;i++)printf("%d\n",ans[i]);
return ;
}

bzoj 4453 cys就是要拿英魂!——后缀数组+单调栈+set的更多相关文章

  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\)),显然我们不能直接比较\( ...

  10. bzoj 4453 cys就是要拿英魂! —— 后缀数组+单调栈+set

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4453 这种问题...一般先把询问离线,排序: 区间对后缀排名的影响在于一些排名大而位置靠后的 ...

随机推荐

  1. netbeans等宽字体却不支持中文

    一直用netbeans,各方面都很满意,就是这字体十分不爽,如用等宽字体却不支持中文,百度了一下,找到了解决办法,贴出来,给需要的朋友. 01.找到自己java字体目录.我的目录是[C:\Progra ...

  2. Curator学习

    Curator是对zookeeper的高级封装. 考虑到使用它来开发zookeeper应用的方便,特此来记录总结学习与开发使用过程的问题. 1. curator-framework Curator F ...

  3. vs2017创建dotnetcore web项目,并部署到centos7上

    一.打开vs2017创建web项目 二.简单的创建项目后,发布项目 三. 在centos上创建webroot目录,将发布的项目文件复制到该目录下(本人用虚拟机测试) 四.在webroot目录下打开终端 ...

  4. 使用display:table使两栏布局高度相等

    两栏布局大家应该经常用了,但是遇到坑爹的要两栏的高度对齐的话要怎么办呢? <!DOCTYPE html> <html> <head> <meta charse ...

  5. GPL,BSD,Apache,MIT开源许可协议

    在linux环境下学习的多了,这些开源协议也听的见的越来越多,感觉有必要仔细了解一下. 1. BSD 先说BSD是因为它的自由度相对来说是比较大的.BSD全称Berkeley Software Dis ...

  6. NumPy副本和视图

    NumPy - 副本和视图 在执行函数时,其中一些返回输入数组的副本,而另一些返回视图. 当内容物理存储在另一个位置时,称为副本. 另一方面,如果提供了相同内存内容的不同视图,我们将其称为视图. 无复 ...

  7. glance cache

    用在多个glance API server 中,对相同的image文件提供服务.该cache对用户透明. 配置文件有一个image_cache_max_size,超过的话image cache会被修剪 ...

  8. ubuntu16.04 添加中文ibus输入法

    ubuntu版本 16.04 在terminal  输入命令 sudo apt-get install ibus-pinyin sudo apt-get ibus-setup 设置 选择拼音,添加选择 ...

  9. hdu1695莫比乌斯反演模板题

    hdu1695 求1<=i<=n&&1<=j<=m,gcd(i,j)=k的(i,j)的对数 最后的结果f(k)=Σ(1<=x<=n/k)mu[x]* ...

  10. js监测滚动条到达最底边

    scroll : function(){ $(window).scroll(function () { var scrollTop = $(this).scrollTop(); var scrollH ...