【bzoj4491】我也不知道题目名字是什么 离线扫描线+线段树
题目描述
给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串
输入
第一行n,表示A数组有多少元素
接下来一行为n个整数A[i]
接下来一个整数Q,表示询问数量
接下来Q行,每行2个整数l,r
输出
对于每个询问,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串
样例输入
9
1 2 3 4 5 6 5 4 3
5
1 6
1 7
2 7
1 9
5 9
样例输出
6
6
5
6
4
题解
离线扫描线+线段树
考虑询问 $[l,r]$ ,对于选出子串的左端点i,右端点一定是 $min(pos[i],r)$ ,其中 $pos[i]$ 表示从 $i$ 开始的最长不上升子串的最终位置。
那么我们先扫一遍整个序列,求出从每个位置开始的最长不上升子串的最终位置。
然后把 $min(pos[i],r)$ 分为两种情况,即求满足 $pos[i]\le r$ 的所有i中最大的 $pos[i]-i$ ,和满足 $pos[i]>r$ 的所有 $i$ 中最大的 $r-i$(即最大的 $-i$ )
把序列位置看作 $(i,pos[i])$,询问看作 $(l,r)$ ,相当于二维平面上的点,显然这个问题可以用离线扫描线+线段树的方法来解决。
把序列位置按照 $pos[i]$ 从小到大排序,把询问按照 $r$ 从小到大排序。对于 $pos[i]\le r$ 的情况,从前往后扫描询问,把所有 $pos[i]\le r$ 的 $i$ 在线段树的 $i$ 的位置加入 $pos[i]-i$ ,询问直接在线段树求 $[l,r]$ 的最大值。 $pos[i]>r$的情况同理。
时间复杂度 $O(n\log n)$
#include <cstdio>
#include <algorithm>
#define N 50010
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
using namespace std;
struct data
{
int l , r , id;
bool operator<(const data &a)const {return r < a.r;}
}v[N << 1] , q[N];
int a[N] , tot , mx[N << 2] , ans[N];
void build(int l , int r , int x)
{
mx[x] = -1 << 30;
if(l == r) return;
int mid = (l + r) >> 1;
build(lson) , build(rson);
}
void update(int p , int v , int l , int r , int x)
{
mx[x] = max(mx[x] , v);
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(p , v , lson);
else update(p , v , rson);
}
int query(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return mx[x];
int mid = (l + r) >> 1 , ans = -1 << 30;
if(b <= mid) ans = max(ans , query(b , e , lson));
if(e > mid) ans = max(ans , query(b , e , rson));
return ans;
}
int main()
{
int n , m , i , p;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
for(p = i = 1 ; i <= n ; i ++ )
if(a[i] < a[i - 1])
while(p < i)
v[++tot].l = p ++ , v[tot].r = i - 1;
while(p <= n) v[++tot].l = p ++ , v[tot].r = n;
for(p = i = 1 ; i <= n ; i ++ )
if(a[i] > a[i - 1])
while(p < i)
v[++tot].l = p ++ , v[tot].r = i - 1;
while(p <= n) v[++tot].l = p ++ , v[tot].r = n;
scanf("%d" , &m);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &q[i].l , &q[i].r) , q[i].id = i;
sort(v + 1 , v + tot + 1) , sort(q + 1 , q + m + 1);
build(1 , n , 1);
for(p = i = 1 ; i <= m ; i ++ )
{
while(p <= tot && v[p].r <= q[i].r) update(v[p].l , v[p].r - v[p].l + 1 , 1 , n , 1) , p ++ ;
ans[q[i].id] = max(ans[q[i].id] , query(q[i].l , q[i].r , 1 , n , 1));
}
build(1 , n , 1);
for(p = tot , i = m ; i ; i -- )
{
while(p && v[p].r > q[i].r) update(v[p].l , -v[p].l , 1 , n , 1) , p -- ;
ans[q[i].id] = max(ans[q[i].id] , query(q[i].l , q[i].r , 1 , n , 1) + q[i].r + 1);
}
for(i = 1 ; i <= m ; i ++ ) printf("%d\n" , ans[i]);
return 0;
}
【bzoj4491】我也不知道题目名字是什么 离线扫描线+线段树的更多相关文章
- BZOJ4491: 我也不知道题目名字是什么
Description 给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串 Input 第一行n,表示A数组有多少元素接下来一行为n个整数A[i]接下来一 ...
- 2019.03.09 bzoj4491: 我也不知道题目名字是什么(线段树)
传送门 题意:给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串. 思路: 注意要求的是子串而不是子序列!!! 然后直接用线段树维护最大子段和的方式合并一 ...
- 【BZOJ4491】我也不知道题目名字是什么 [线段树]
我也不知道题目名字是什么 Time Limit: 10 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 给定一个序列A[i ...
- 【BZOJ4991】我也不知道题目名字是什么(线段树)
[BZOJ4991]我也不知道题目名字是什么(线段树) 题面 BZOJ 题解 对于线段树维护的区间维护以下东西: 区间左(右)端开始(结束)的最长(短)子串的长度 左端右端的值,以及当前区间内的答案 ...
- BZOJ 4491: 我也不知道题目名字是什么
4491: 我也不知道题目名字是什么 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 278 Solved: 154[Submit][Status][ ...
- BZOJ 4491: 我也不知道题目名字是什么 RMQ
4491: 我也不知道题目名字是什么 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 317 Solved: 174[Submit][Status][ ...
- 【洛谷4770/UOJ395】[NOI2018]你的名字(后缀数组_线段树合并)
题目: 洛谷4770 UOJ395 分析: 一个很好的SAM应用题-- 一句话题意:给定一个字符串\(S\).每次询问给定字符串\(T\)和两个整数\(l\).\(r\),求\(T\)有多少个本质不同 ...
- BZOJ 4491: 我也不知道题目名字是什么 线段树+离线
code: #include <string> #include <cstring> #include <cstdio> #include <algorith ...
- [NOI2018]你的名字(后缀自动机+线段树)
题目描述 小A 被选为了ION2018 的出题人,他精心准备了一道质量十分高的题目,且已经把除了题目命名以外的工作都做好了. 由于ION 已经举办了很多届,所以在题目命名上也是有规定的,ION 命题手 ...
随机推荐
- 【转】Odoo开发之:工作流 workflow
在OpenERP中,工作流是管理一组“所做的事情”(与一些数据模型的记录关联)的人为现象.工作流提供了高级别的方式来组织记录要上做的事情. 具体地说,工作流是一个定向的路径,这里节点称为活动并且弧线称 ...
- BZOJ3293_分金币_KEY
题目传送门 设x[i]表示i+1向i传的糖果数,x[n]表示1向n传的糖果数,a'=(a[1]+...a[N])/N a[1]+x[1]−x[n]=a' a[2]+x[2]−x[1]=a' a[3]+ ...
- 如果看懂git -help
每一个git 命令,都可以git * --help 打开git 的网页去看详细内容,也可以git * -help 在当前命令行里面看. 如下: zy@caoxinyu MINGW64 /f/git/i ...
- 关于Python的多重排序
Python预置的list.sort().sorted()方法可实现各种数组的排序,但支持的只限于一个key,如果要多重排序,目前所知的方法只有自定义了. Help on built-in funct ...
- 使用 adb 命令一次性为多个设备安装 apk
使用 adb 命令一次性为多个设备安装 apk 原创 2016年07月15日 10:40:53 3154 命令简介 adb install [-lrtsdg] (file) 把包文件推送到设备上并安装 ...
- Jmeter登录接口返回 status415
1.现象:在查看结果树中看到: Request Headers:Connection: keep-aliveContent-Type: application/x-www-form-urlencode ...
- Unity编辑器 - 鼠标悬停在控件上时改变鼠标样式
Unity编辑器 - 鼠标悬停在控件上时改变鼠标样式 摘自Unity文档 EditorGUIUtility.AddCursorRect public static void AddCursorRect ...
- C if语句判断年龄
#include <stdio.h> int main(int argc, char **argv) { //新建两个变量给变量赋值跟初始化:const int a=45;int c=0; ...
- Struts2(九.利用layer组件实现图片显示功能)
1.layer前端组件介绍 layer是一款口碑极佳的web弹层组件,她具备全方位的解决方案,致力于服务各个水平段的开发人员,您的页面会轻松地拥有丰富而友好的操作体验. http://sentsin. ...
- lintcode174 删除链表中倒数第n个节点
删除链表中倒数第n个节点 给定一个链表,删除链表中倒数第n个节点,返回链表的头节点. 注意事项 链表中的节点个数大于等于n 您在真实的面试中是否遇到过这个题? Yes 样例 给出链表1->2 ...