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+5; int n,m,tax[xn],tp[xn],sa[xn],rk[xn],sta[xn],top,dc[xn],ht[xn][20],bin[20],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=0,f=1; char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();return f?ret:-ret; } void Rsort() {for(int i=1;i<=m;i++)tax[i]=0;for(int i=1;i<=n;i++)tax[rk[tp[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]; } void work() {for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;Rsort();for(int k=1;k<=n;k<<=1){int num=0;for(int i=n-k+1;i<=n;i++)tp[++num]=i;for(int i=1;i<=n;i++)if(sa[i]>k)tp[++num]=sa[i]-k;Rsort(); swap(rk,tp);rk[sa[1]]=1; num=1;for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num;if(num==n)break;m=num;} } void get() {int k=0;for(int i=1;i<=n;i++){if(rk[i]==1)continue;if(k)k--; int j=sa[rk[i]-1];while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;ht[rk[i]][0]=k;}bin[0]=1; for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1);r[1]=0; for(int i=2;i<=n;i++)r[i]=r[i>>1]+1;for(int j=1;j<20;j++)for(int i=1;i<=n&&i+bin[j]-1<=n;i++)ht[i][j]=min(ht[i][j-1],ht[i+bin[j-1]][j-1]);// } 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+1];return min(ht[x][w],ht[y-bin[w]+1][w]);// } int main() {scanf("%s",s+1); n=strlen(s+1);for(int i=1;i<=n;i++)dc[i]=(int)s[i];sort(dc+1,dc+n+1); m=unique(dc+1,dc+n+1)-dc-1;for(int i=1;i<=n;i++)s[i]=lower_bound(dc+1,dc+m+1,(int)s[i])-dc;work(); get();int Q=rd();for(int i=1;i<=Q;i++)q[i].l=rd(),q[i].r=rd(),q[i].id=i;sort(q+1,q+Q+1,cmp); int p=0;for(int i=1;i<=Q;i++){while(p<q[i].r){p++; int y;while(rk[y=sta[top]]<rk[p]&&top)//< {int pos=min(n+1,p+getlcp(y,p));v[pos].pb(y); com[p].pb(y);top--;}sta[++top]=p; st.insert(p);for(int i=0,x;i<v[p].size();i++)if(st.count(x=v[p][i])){for(int j=0;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=1;i<=Q;i++)printf("%d\n",ans[i]);return 0; }
转载于:https://www.cnblogs.com/Zinn/p/10083295.html
bzoj 4453 cys就是要拿英魂! —— 后缀数组+单调栈+set相关推荐
- ●BZOJ 4453 cys就是要拿英魂!
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4453 题解: 后缀数组,离线询问,栈 看了一堆题解才看懂,太弱啦 ~ 如果对于一个区间[l, ...
- [BZOJ 3238] [AHOI 2013] 差异 【后缀数组 + 单调栈】
题目链接:BZOJ - 3238 题目分析 显然,这道题就是求任意两个后缀之间的LCP的和,这与后缀数组的联系十分明显. 求出后缀数组后,求出字典序相邻两个后缀的LCP,即 Height 数组. 那么 ...
- bzoj 3238: [Ahoi2013]差异(后缀数组+单调栈)
3238: [Ahoi2013]差异 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 3443 Solved: 1562 [Submit][Stat ...
- [Ahoi2013]差异[后缀数组+单调栈]
链接 解题思路:很明显前面∑1<=i<j<=nlen(Ti)+len(Tj)\sum_{1<=i<j<=n}len(T_i)+len(T_j)∑1<=i< ...
- 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累加的 ...
- 【BZOJ3238】差异,后缀数组+单调栈维护height
Time:2016.05.23 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 题意已经说的很明白了. 关键在于如何快速求得各lcp的和 有一个重要的性质 排名为i和j(i<j ...
最新文章
- 21、C#里面类的创建和使用
- 2264: sequence(KMP)
- Python基础——细琐知识点
- 推荐:个人时间跟踪工具 ManicTime
- [剑指offer]面试题第[35]题[Leetcode][第138题][JAVA][复杂链表的复制][暴力][HashMap][复制链表]
- php curl cookie,php中curl获取返回页面的cookie
- 肉袒牵羊的拼音及解释
- Codeforces Round #197 (Div. 2): C. Xenia and Weights(记忆化搜索)
- 【转】Elasticsearch+Django搜索引擎(一)
- 25个jQuery的编程小抄
- Python 高级编程笔记之测试驱动开发
- 和平精英怎么玩?智能找图、鼠标滚轮宏按键玩吃鸡还能匹配手机?
- 麦克风阵列入门(一)
- 中小幼计算机等级培训,全国中小学教师教育技术水平考试考试系统使用培训0817.pptx...
- hds linux 识别盘符,HDS HDLM让集群两边认到的盘符一样
- KY-RTI分布仿真技术:第四章 C++程序设计
- IDEA连接数据库自动生成model(get set方法)
- nds运行java_NDS看漫画软件 Comic Book DS 1.0 正式版!
- HTML5初学——列表标签(09-12课)和表单标签(13-30课)、查阅文档
- 你可知道,让你发胖的食物不是高脂肪食物,而是高碳水化合物
热门文章
- windows linux 共存,Windows与Linux共存
- 批处理学习(一)——MS-DOS命令
- 拿信用卡套个首付买房子——引火自焚
- 数据库系统概论(第5版)王珊 详细知识清单 期末复习速成 考前冲刺 面试——(第一篇 基础篇)
- 17、springcloud整合lettuce使用redis
- 微信群导出群成员时间数据_教你一招轻松导出微信群名单
- 心知天气api PHP,心知天气API的应用实例
- 那些好玩的生成器网站(二)
- 百度地图API获取行政区域边界(省、市、区县)
- 鄱.阳.湖.7月13日遥感数据汇总及共享