CF1693D--单调区间
\(T_4\) 单调区间结题报告
题目描述
一句话题意:给定一个排列 \(a\) 算出有多少个区间 \([l , r]\) , 满足其可以划分为一个单调递增子序列和单调递减子序列,其中单调递增子序列长度 \(\ge 1\) , 单调递减子序列长度可为 \(0\) . \(n \le 10 ^ 5\)
题解
呃呃能自己想出来挺不容易的,废了老子一下午一晚上。
感觉大家在证分治做法的复杂度,我也不淌这潭浑水了,本做法为 \(n \log n\) , 使用树状数组和优先队列数据结构。
首先考虑一个结论,对于一个不满足条件的区间 \([a , b]\) ,其一定满足如下条件:
对于 \(a \le i < j < k < l \le b\) , 满足:
\[a_k < a_l < a_i < a_j \ \lor \ a_j < a_i < a_l < a_k \ \ \ \ \ \ \ \ \ \ \ (1)
\]
手模一下就能发现这样构成不了合法解。
两个图:(图是反的)

我们又发现假设我们目前为 \(l\) , 那么对于上面的结论来说,去找最大满足上述结论的 \(\max\{i\}\) .
那么 \(l\) 贡献出的答案为 $$l - \max{i}$$
当然,我们称 \(\max\{i\}\) 为 \(l\) 的左端点 \(L_l\)
对于 \(\alpha < l\) , 那么 \([i , l] \ \left(i \le L_{\alpha}\right)\) 区间同样取不到。
于是得到进阶结论:
对于排列 \(a\) : ( \(L\) 定义不变 )
\[ans = \sum_{i = 1}^{n} i - \max_{1 \le j \le i}\{L_j\} \ \ \ \ \ \ \ \ \ \ (2)
\]
然后我们考虑去求 \(L_i\)
我们对于结论 \(1\) 来说,可以分成或左或右两方分讨。
对于一种情况来说 (假设为第一种) , 设目前为 \(d\) .
让目前那四个数为 \(a , b , c , d\)
一个显然的结论:
我们如果为了让 \(L_d\) 最小,\(c\) 一定是离 \(d\) 最近,且 \(a_c > a_d\) 的点。
贪心显然
于是我们可以去枚举 \(c\) , 以 \(c\) 为下标存储 \(d\) .
那我们求 \(L_d\) 时 , 显然是某个 \(1 \le i < c\) , 且 \(i\) 满足 \(a_i < a_d \ \land \ \exists \ j : i < j < c , a_j < a_i\) .
其实无脑一下就是上图中(后面的图) 最后一个大于第一个,第一个大于第二个,找下标最大的第一个。
所以可以开一个树状数组,就是以 \(a_i\) 为下标,维护 \(i\) .
(有人有疑惑为什么不从图中第二个位置转移吗? 那样看起来还好处理一点)
错误点在于第二个点要从比他大的转移来,然而比他大的怎么就一定比 \(a_d\) 小呢?
例子: \(3 , 100 , 2 , 1000 , 5\)
如果你从 你按你的想法查 \(2\) , 查出来的位置是 \(2\) . 不合法。
因此需要算,如果存在一个比 \(a_i\) 小的数刚刚加进来,就可以把 \(i\) ,扔进树状数组了。
具体可以用一个大根堆,在枚举 \(c\) ,并处理完 \(d\) 后,将所有在优先队列中大于 \(a_c\) 的数加进树状数组(此时的 \(c\) 就是后面某次的 \(b\) 啊!) 差的时候查 \([1 , a_i)\) 中下标最大值 (显然是插进树状数组中的的才可以转移)。
对于第一个图,处理差不多,不再赘述。
然而就是说第一个图,要求 \(\max\limits_{i < j \le n}\{val_j\}\)
( \(val\) 是树状数组维护的值 )
即后缀和。我们只需要把输转数组反过来存, \(n - i + 1\) 存 \(i\) .
\(Code\)
CODE
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define int long long
#ifdef linux
#define getchar getchar_unlocked
#endif
using namespace std ;
using namespace __gnu_pbds ;
using namespace __gnu_cxx ;
typedef long long ll ;
const int N = 4e5 + 100 ;
inline int read() {
int x = 0 , f = 1 ;
char c = getchar() ;
while (c < '0' || c > '9') {
if (c == '-') f = -f ;
c = getchar() ;
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0' ;
c = getchar() ;
}
return x * f ;
}
int n ; int a[N] ; int Ans[N] ;
struct Binary_Index_Array_Max {
#define lowbit(x) (x & (- x))
int t[N] ;
void clear() {
memset(t , 0 , sizeof(t)) ;
}
void add(int pos , int val) {
while (pos <= n) {
t[pos] = max(t[pos] , val) ;
pos += lowbit(pos) ;
}
}
int Query(int pos) {
int ans = 0 ;
while (pos > 0) {
ans = max(t[pos] , ans) ;
pos -= lowbit(pos) ;
}
return ans ;
}
} t1 , t2 ;
int front1[N] , front2[N] ;
vector <int> v1[N] , v2[N] ;
__gnu_pbds :: priority_queue <int , less<int> > q1 ;
__gnu_pbds :: priority_queue <int , greater<int> > q2 ;
int pos[N] ;
signed main() {
n = read() ;
for (int i = 1 ; i <= n ; ++ i) a[i] = read() , pos[a[i]] = i ;
for (int i = 1 ; i <= n ; ++ i) {
front1[i] = t1.Query(n - a[i] + 1) ; v1[front1[i]].push_back(i) ;
front2[i] = t2.Query(a[i]) ; v2[front2[i]].push_back(i) ;
t1.add(n - a[i] + 1 , i) ; t2.add(a[i] , i) ;
} t1.clear() ;
for (int i = 1 ; i <= n ; ++ i) {
for (auto j : v1[i]) {
Ans[j] = t1.Query(a[j] - 1) ;
}
while (!q1.empty()) {
int x = q1.top() ;
if (x <= a[i]) break ; q1.pop() ;
t1.add(x , pos[x]) ;
} q1.push(a[i]) ;
} t1.clear() ;
for (int i = 1 ; i <= n ; ++ i) {
for (auto j : v2[i]) {
Ans[j] = max(Ans[j] , t1.Query(n - (a[j] + 1) + 1)) ;
}
while (!q2.empty()) {
int x = q2.top() ;
if (x >= a[i]) break ; q2.pop() ;
t1.add(n - x + 1 , pos[x]) ;
} q2.push(a[i]) ;
}
int Ansp = 0 ;
for (int i = 1 ; i <= n ; ++ i) {
Ans[i] = max(Ans[i] , Ans[i - 1]) ;
Ansp += i - Ans[i] ;
}
cout << Ansp << '\n' ;
}
CF1693D--单调区间的更多相关文章
- ACM学习历程—BestCoder 2015百度之星资格赛1006 单调区间(组合数学)
Problem Description 百小度最近在逛博客,然后发现了一个有趣的问题. 如下图所示,是一个12 位数014326951987 , 它的数字先逐渐变大, 然后变小,再变大,接着变小,又变 ...
- [转]趣题:一个n位数平均有多少个单调区间?---- From Matrix67
考虑这么一个 14 位数 02565413989732 ,如图所示,它的数字先逐渐变大,然后开始变小,再变大,再变小,再变大,再变小.我们就说,它一共包含了 6 个单调区间.我们的问题就是:一个 n ...
- bestcoder单调区间
http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=584&pid=1006 题解:ORZ Matrix67 ht ...
- HDU 3308 LCIS 线段树区间更新
最近开始线段树一段时间了,也发现了不少大牛的博客比如HH大牛 ,小媛姐.这个题目是我在看HH大牛的线段树专题是给出的习题,(可以去他博客找找,真心推荐)原本例题是POJ3667 Hotel 这个题目 ...
- hdu 单调队列
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4122 代码: #include<cstdio> #include<iostream& ...
- 小结:单调栈 & 单调队列
概要: 对于维护信息具有单调性的性质或者问题可以转化为具有单调性质的模型的题,我们可以考虑用单调栈或单调队列. 技巧及注意: 技巧很多,只要能将问题转化为单调性问题,就好解决了. 当维护固定长度的单调 ...
- [CSP-S模拟测试]:小P的单调数列(树状数组+DP)
题目描述 小$P$最近喜欢上了单调数列,他觉得单调的数列具有非常多优美的性质.经过小$P$复杂的数学推导,他计算出了一个单调增数列的艺术价值等于该数列中所有书的总和.并且以这个为基础,小$P$还可以求 ...
- P3512 [POI2010]PIL-Pilots 单调队列的应用
题目描述 给定n,k和一个长度为n的序列,求最长的最大值最小值相差不超过k的序列 输入格式 第一行两个有空格隔开的整数k(0<=k<=2000,000,000),n(1<=n< ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- BUG-FREE-For Dream
一直直到bug-free.不能错任何一点. 思路不清晰:刷两天. 做错了,刷一天. 直到bug-free.高亮,标红. 185,OA(YAMAXUN)--- (1) findFirstDuplicat ...
随机推荐
- selenium窗口之间的切换
import time from selenium.webdriver import Edge from selenium.webdriver.common.by import By from sel ...
- LAMP-CentOS7搭建Web服务器
搭建LAMP Web服务器 在家中翻到了以前用的老电脑,在思索一番后,决定把这台电脑改造成一台Web服务器,作为我自己搭建博客的测试机器. 一.Linux服务器 LAMP中的L指的是Linux服务器, ...
- 使用jsp+servlet+mysql用户管理系统之用户注册-----------使用简单三层结构分析页面显示层(view),业务逻辑层(service),数据持久层(dao)
View层:jsp+servlet: jsp: <%@ page language="java" contentType="text/html; charset=U ...
- 不是人家太装逼,而是我们太low
在一个社团的迎新的时候,每个人自我介绍.等到一个一身LV,爱马仕的女孩子自我介绍,说起爱好,她想了想说:喜欢跑车.然后很淡定的坐下了.很多同学你看我我看你,投以"炫富"的判断目光- ...
- 记一次win10 python -m http.server 启动后无法访问的经历
前言 最近需要在win10上使用python创建一个http文件服务(默认端口 8000),结果执行了 python3 -m http.server -b 0.0.0.0 后,发现服务跑起来了,但浏览 ...
- Java开发框架演变过程
JavaWeb开发简史 Java框架创始人 Java框架说明 Spring: 把应用程序中的bean统一交给Spring进行管理控制,简化了我们的代码操作,和降低了代码的耦合度,Spring框架基本上 ...
- react 拖拽组件 自由拖拽,垂直水平拖拽
react拖拽组件 推荐几个不错的开源拖拽组件以及使用方法 第一个拖拽组件 antd的Tree组件 这个拖拽组件经常用于层级关系的拖拽组件 可以动态的增删改 (排序,添加子层级~父层级,修改等). i ...
- 使用post请求登陆
1.使用post请求登陆 import requests import matplotlib.pyplot as plt url = 'https://www.ptpress.com.cn/login ...
- Django集成的密码找回功能
要实现忘记密码功能,您需要进行以下修改: 添加忘记密码链接到登录页面. 创建密码丢失修改页面. 创建密码修改页面. 编写相应的视图函数来处理密码丢失修改和密码修改逻辑. 编写发送验证信息到邮箱的逻辑. ...
- linux date格式化获取时间
转载请注明出处: 在编写shell脚本时,需要在shell脚本中格式化时间,特此整理下date命令相关参数的应用 root@controller1:~# date --help 用法:date [选项 ...