bzoj4453
单调栈+set+后缀数组
一道奇妙的题
这道题如果对于每个询问$r$是固定的,那么就很简单了,可惜并不是
由于r会变化,那么对于两个子串$[i...r],[j...r]$,他们的大小关系随着r的变化也会变化,使得我们不能直接预处理答案
所以我们把询问离线,把每个询问按照r分类,通过考虑r的变化来完成询问
对于两个后缀$[i...r],[j...r],(i<j)$,设他们的$lcp=l$,那么当$l∈[j,j+l-1]$时,$[i...r]>[j...r]$,当$r=j+l$时,则变成$[i...r]<[j...r]$,因为$s[i+l]<s[j+l]$(假设)
我们称这样的两个后缀为$i$伴随$j$。
那么我们对答案维护一个set,里面存着一些后缀,保证后缀当前的大小单调递减,这样我们就可以每次快速询问答案。
但是由于$r$的变化每次大小关系会改变,也就是我们要把一些后缀删掉
那么我们再维护一个单调栈,这里存的是严格的后缀大小,这个单调栈是为了给每个新加入的后缀求出哪些后缀伴随他
那么如果当前的栈顶是大于新的后缀,$break$,否则标记$top$伴随$i$,并且记录当$i$,也就是$r=i+lcp$时删除栈顶
每次删除一个元素时,伴随他的元素也应该删除,所以每次$dfs$删除即可,并在$set$里删除
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #include <set>
- #include <vector>
- using namespace std;
- const int N = 1e5 + ;
- int n, k, m, top;
- int rnk[N], tmp[N], sa[N], ans[N], vis[N], st[N], h[N][], Log[N];
- char s[N];
- set<int> S;
- vector<pair<int, int> > v[N];
- vector<int> del[N], g[N];
- bool cmp(int i, int j) {
- if(rnk[i] != rnk[j]) {
- return rnk[i] < rnk[j];
- }
- int ri = i + k <= n ? rnk[i + k] : -;
- int rj = j + k <= n ? rnk[j + k] : -;
- return ri < rj;
- }
- void dfs(int u) {
- vis[u] = ;
- S.erase(u);
- for(int i = ; i < g[u].size(); ++i) {
- if(!vis[g[u][i]]) {
- dfs(g[u][i]);
- }
- }
- }
- void SA() {
- for(int i = ; i <= n; ++i) {
- sa[i] = i;
- rnk[i] = s[i];
- }
- for(k = ; k <= n; k <<= ) {
- sort(sa + , sa + n + , cmp);
- tmp[sa[]] = ;
- for(int i = ; i <= n; ++i) {
- tmp[sa[i]] = tmp[sa[i - ]] + (cmp(sa[i - ], sa[i]));
- }
- for(int i = ; i <= n; ++i) {
- rnk[i] = tmp[i];
- }
- }
- for(int i = ; i <= n; ++i) {
- rnk[sa[i]] = i;
- }
- int d = ;
- for(int i = ; i <= n; ++i) {
- if(rnk[i] <= ) {
- continue;
- }
- int j = sa[rnk[i] - ];
- if(d) {
- --d;
- }
- for(; i + d <= n && j + d <= n; ++d) {
- if(s[i + d] != s[j + d]) {
- break;
- }
- }
- h[rnk[i] - ][] = d;
- }
- for(int j = ; j <= ; ++j) {
- for(int i = ; i + ( << j) - <= n; ++i) {
- h[i][j] = min(h[i][j - ], h[i + ( << (j - ))][j - ]);
- }
- }
- }
- int rmq(int l, int r) {
- if(l == r) {
- return n - l + ;
- }
- l = rnk[l];
- r = rnk[r];
- if(l > r) {
- swap(l, r);
- }
- --r;
- int x = Log[r - l + ];
- return min(h[l][x], h[r - ( << x) + ][x]);
- }
- int main() {
- scanf("%s%d", s + , &m);
- n = strlen(s + );
- for(int i = ; i <= n; ++i) {
- Log[i] = Log[i >> ] + ;
- }
- SA();
- for(int i = ; i <= m; ++i) {
- int l, r;
- scanf("%d%d", &l, &r);
- v[r].push_back(make_pair(l, i));
- }
- for(int i = ; i <= n; ++i) {
- S.insert(i);
- while(top) {
- int lcp = rmq(st[top], i);
- if(s[st[top] + lcp] > s[i + lcp]) {
- break;
- }
- del[i + lcp].push_back(st[top]);
- g[i].push_back(st[top]);
- --top;
- }
- st[++top] = i;
- for(int j = ; j < del[i].size(); ++j) {
- if(!vis[del[i][j]]) {
- dfs(del[i][j]);
- }
- }
- for(int j = ; j < v[i].size(); ++j) {
- pair<int, int> x = v[i][j];
- ans[x.second] = *S.lower_bound(x.first);
- }
- }
- for(int i = ; i <= m; ++i) {
- printf("%d\n", ans[i]);
- }
- return ;
- }
bzoj4453的更多相关文章
- 【BZOJ4453】cys就是要拿英魂! 后缀数组+单调栈+set
[BZOJ4453]cys就是要拿英魂! Description pps又开始dota视频直播了!一群每天被pps虐的蒟蒻决定学习pps的操作技术,他们把pps在这局放的技能记录了下来,每个技能用一个 ...
随机推荐
- cocos2d-x AssetsManager libcurl使用心得
libcurl使用心得 最新正在写cocosclient更新的逻辑.研究了一下cocos2d-x自带的Libcurl,下面是自己在使用过程中的心得和遇到的未解问题.希望大家一起讨论一下,欢迎大家指导. ...
- ABAP 弹出框 函数
POPUP_GET_VALUES_USER_HELP 是一个和用户交互信息的函数,用户能够填写信息,并且我们还能够依据实际的需求对弹出框进行F1 F4 以及用户的需求进行增强.具体的实现能够參考系统标 ...
- 九度OJ 1078:二叉树遍历 (二叉树)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3748 解决:2263 题目描述: 二叉树的前序.中序.后序遍历的定义: 前序遍历:对任一子树,先访问跟,然后遍历其左子树,最后遍历其右子树 ...
- 九度OJ 1076:N的阶乘 (数字特性、大数运算)
时间限制:3 秒 内存限制:128 兆 特殊判题:否 提交:6384 解决:2238 题目描述: 输入一个正整数N,输出N的阶乘. 输入: 正整数N(0<=N<=1000) 输出: 输入可 ...
- centos 7 官网安装 PostgreSQL
https://www.postgresql.org/download/linux/redhat/
- php微信支付测试开发(流程已通)
必要条件: appid //公众号后台开发者中心获得(和邮件内的一样) mchid//邮件内获得 key//商户后台自己设置 appsecret //公众号开发者中心获得 两个证书文件,邮件内 ...
- 《Python Machine Learning》索引
目录部分: 第一章:赋予计算机从数据中学习的能力 第二章:训练简单的机器学习算法——分类 第三章:使用sklearn训练机器学习分类器 第四章:建立好的训练集——数据预处理 第五章:通过降维压缩数据 ...
- bind(),live(),delegate(),on()绑定事件方式
1.bind():向匹配元素添加一个或多个事件处理器. 适用所有版本,但是自从jquery1.7版本以后bind()函数推荐用on()来代替. $(selector).bind(event,data, ...
- YxdJSON - Delphi 高性能 JSON 库(支持RTTI和序列化操作)
源:YxdJSON - Delphi 高性能 JSON 库(支持RTTI和序列化操作) Delphi 高性能 JSON 库(支持RTTI和序列化操作) 支持平台: Windows, Android, ...
- nodejs中的子进程,深入解析child_process模块和cluster模块
Node.js的进程管理 node遵循的是单线程单进程的模式,node的单线程是指js的引擎只有一个实例,且在nodejs的主线程中执行,同时node以事件驱动的方式处理IO等异步操作.node的 ...