后缀数组+单调栈+set--bzoj4453: cys就是要拿英魂!
传送门
好题!!!
介于是一道权限题所以我就粘题面吧···
Description
pps又开始dota视频直播了!一群每天被pps虐的蒟蒻决定学习pps的操作技术,他们把pps在这局放的技能记录了下
来,每个技能用一个字符表示。经过研究,蒟蒻们发现字典序更大的连招威力更大。于是所有蒟蒻都想学习pps最
强的连招。但是他们太弱了,不能学会整个视频里的连招,只能学会陈老师一段区间间内的连招,可是这个他们求
不出,于是只好向你求助。为了蒟蒻们不再被pps虐(怎么可能),请你帮帮他们。简化题意:给你一个字符串,
每次询问你一段区间的字典序最大的子串。
Input
第一行是一个字符串S,表示pps放的技能
第二行一个正整数Q,表示询问个数
接下来Q行,每行两个正整数[l,r],表示询问区间[l,r]中的字典序最大的子串。
Output
Q行,每行一个正整数,表示该区间内字典序最大的子串的起始位置。
Sample Input
Lets_go_mod_p!
5
2 2
3 3
2 5
1 10
2 9
Sample Output
2
3
3
3
3
数据范围:
1<=|S|<=100000
1<=Q<=100000
1<=l<=r<=|S|
一开始看到题的时候推了推性质(还有这种题询问这么多不是数据结构维护就是离线要么就是二分,显然不能数据结构也不能二分,所以只能是离线了)
对于两个后缀i,j(i<j)i,j(i<j)i,j(i<j):
若rk[i]>rk[j]rk[i]>rk[j]rk[i]>rk[j],不用管。
若rk[i]<rk[j]rk[i]<rk[j]rk[i]<rk[j],那么对于一些询问的RRR,若R≤j+lcp(i,j)−1R\le j+lcp(i,j)-1R≤j+lcp(i,j)−1,这个时候应该是rk[i]rk[i]rk[i]要更大些,因为后面的字母会被截断,若R>j+lcp(i,j)−1R>j+lcp(i,j)-1R>j+lcp(i,j)−1,就是rk[j]rk[j]rk[j]更大。
所以我们一定是离线之后往过扫,一边修改,一定是给j+lcp(i,j)j+lcp(i,j)j+lcp(i,j)的地方打个标记什么的,但想到这我就不会了
其实就是一个很神奇的操作
用单调栈优化setsetset,简单来说就是维护了两种边,一种是伴随边,一种是删除边,当r+1r+1r+1的时候,要把r+1r+1r+1处的删除边连的点都删掉,然后把删掉的点的伴随点也删掉,然后答案就是setsetset里面LLL的后继
因为后缀排序写错wawawa了半天,还有lcplcplcp那里是用rankrankrank来求的
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#define maxn 200005
#define LL long long
using namespace std;inline int rd(){int x=0,f=1;char c=getchar();while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();return x*f;
}int n,m,q,tax[maxn],sa[maxn],rk[maxn],tp[maxn],h[maxn],st[maxn][20],ans[maxn];
int stk[maxn],top;
char s[maxn];
set<int> ss;inline void rsort(){for(int i=1;i<=m;i++) tax[i]=0;for(int i=1;i<=n;i++) tax[rk[i]]++;for(int i=1;i<=m;i++) tax[i]+=tax[i-1];for(int i=n;i;i--) sa[tax[rk[tp[i]]]--]=tp[i];
}inline void ssort(){for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;rsort();for(int w=1,p=0;w<=n&&p<n;w<<=1,m=p){p=0;for(int i=n-w+1;i<=n;i++) tp[++p]=i;for(int i=1;i<=n;i++)if(sa[i]>w) tp[++p]=sa[i]-w;rsort(); swap(rk,tp);rk[sa[1]]=p=1;for(int i=2;i<=n;i++)if(tp[sa[i]]==tp[sa[i-1]]&&tp[min(n+1,sa[i]+w)]==tp[min(n+1,sa[i-1]+w)])rk[sa[i]]=p;else rk[sa[i]]=++p;}
}inline void get_h(){int j,k=0;for(int i=1;i<=n;i++){if(k) --k;j=sa[rk[i]-1];while(s[j+k]==s[i+k]) ++k;h[rk[i]]=k;}
}inline void prework(){for(int i=1;i<=n;i++) st[i][0]=h[i];for(int j=1;(1<<j)<=n;j++)for(int i=1;i+(1<<j)-1<=n;i++)//i写成j了我手残 QAQ st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}inline int lcp(int l,int r){l=rk[l],r=rk[r];//!!!if(l>r) swap(l,r); ++l;int k=log2(r-l+1); return min(st[l][k],st[r-(1<<k)+1][k]);
}struct Que{int l,r,id;bool operator <(const Que &x) const{return r<x.r;}
}qu[maxn];int to[maxn],nxt[maxn],head1[maxn],head2[maxn],cnt;//head1 with head2 delete
bool del[maxn];void dfs(int x){del[x]=1; ss.erase(x);for(int i=head1[x];i;i=nxt[i])if(!del[to[i]]) dfs(to[i]);
}inline void add(int ty,int x,int y){if(x>n) return;if(ty) to[++cnt]=y,nxt[cnt]=head1[x],head1[x]=cnt;else to[++cnt]=y,nxt[cnt]=head2[x],head2[x]=cnt;
}int main(){scanf("%s",s+1); n=strlen(s+1); m=127;ssort(); get_h(); prework();q=rd();for(int i=1;i<=q;i++) qu[i].l=rd(),qu[i].r=rd(),qu[i].id=i;sort(qu+1,qu+1+q);int now=1;for(int i=1;i<=q;i++){while(now<=qu[i].r){while(top && rk[stk[top]]<rk[now]){add(0,now+lcp(now,stk[top]),stk[top]),add(1,now,stk[top]);top--;}stk[++top]=now; ss.insert(now);for(int j=head2[now];j;j=nxt[j]) if(!del[to[j]]) dfs(to[j]);++now;}ans[qu[i].id]=*(ss.lower_bound(qu[i].l));}for(int i=1;i<=q;i++) printf("%d\n",ans[i]);return 0;
}
后缀数组+单调栈+set--bzoj4453: cys就是要拿英魂!相关推荐
- [Ahoi2013]差异[后缀数组+单调栈]
链接 解题思路:很明显前面∑1<=i<j<=nlen(Ti)+len(Tj)\sum_{1<=i<j<=n}len(T_i)+len(T_j)∑1<=i< ...
- [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】
题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么 ...
- BZOJ3879: SvT【后缀数组+单调栈】
Description (我并不想告诉你题目名字是什么鬼) 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始 ...
- POJ - 3415 Common Substrings(后缀数组+单调栈)
题目链接:点击查看 题目大意:给出两个字符串,再给出一个k,问两个字符串中长度大于等于k的公共子串有多少个(种类可重复) 题目分析:因为涉及到了子串问题,先用后缀数组跑出height数组来,接下来如果 ...
- [bzoj3238]差异(后缀数组+单调栈)
显然我们可以先把len(Ti)+len(Tj)的值先算出来,再把LCP减去.所有len(Ti)+len(Tj)的值为n*(n-1)*(n+1)/2,这个随便在纸上画一画就可以算出来的. 接下来问题就是 ...
- [BZOJ3238][AHOI2013]差异 [后缀数组+单调栈]
题目地址 - GO-> 题目大意: 给定一个长度为 nn 的字符串SS,令TiTi表示它从第ii个字符开始的后缀,求以下这个式子的值: ∑1≤i<j≤nlen(Ti)+len(Tj)−2× ...
- 【BZOJ3879】SvT,后缀数组+单调栈维护sum
Time:2016.08.15 Author:xiaoyimi 转载注明出处谢谢 如果有不明白的地方可以在下面评论问我 传送门 思路: 建立后缀数组求出Height 如果说对每次询问暴力求LCP累加的 ...
- POJ 3415 后缀数组+单调栈
题目大意: 给定A,B两种字符串,问他们当中的长度大于k的公共子串的个数有多少个 这道题目本身理解不难,将两个字符串合并后求出它的后缀数组 然后利用后缀数组求解答案 这里一开始看题解说要用栈的思想,觉 ...
- bzoj 3238: [Ahoi2013]差异(后缀数组+单调栈)
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 3443 Solved: 1562 [Submit][Stat ...
- 【HAOI2016/BZOJ4566】找相同字符 后缀数组+单调栈
原题走这里 鉴于我实在不是很懂单调栈和单调队列这一系列东西,所以我决定稍微具体讲一下单调栈. 恩,本题实质上就是求两个字符串的公共子串数,其中只要出现位置不同,就算是不同的子串. 处理多个字符串的经典 ...
最新文章
- 没人比程序猿更讨厌软件
- 关于使用jQuery时$(document).ready()方法失效问题
- js实现点击自动下载文件
- .NET(c#) 移动APP开发平台 - Smobiler(1)
- 【OC底层】OC对象本质,如 isa, super-class
- The Double-Checked Locking is Broken Declaration
- [转]OOPC:Object-Oriented Programming in C
- 雷林鹏分享:jQuery EasyUI 数据网格 - 自定义排序
- 算法导论--最小生成树(Kruskal和Prim算法)
- 基于3D人像复原技术的试衣平台
- echarts-python数据可视化大屏展示
- 【自然语言处理】【实体匹配】PromptEM:用于低资源广义实体匹配的Prompt-tuning
- redis主从配置及主从切换
- Python 中文分词 NLPIR 快速搭建
- java 计算体积_java 求体积
- 要你命三千又三千的成长之旅
- 4.17记录 LIS其二
- CANoe.DiVa操作指南——基于DoIP使用CANoe.DiVa用于UDS一致性测试
- NFT Insider #87:The Sandbox 收购游戏开发工作室 Sviper,GHST 大迁徙即将拉开帷幕
- Android Studio代码检查lint使用