Luogu P4093 [HEOI2016/TJOI2016]序列 dp套CDQ
[题面](https://www.luogu.org/problemnew/show/P4093)
好久没写博客了..最近新学了CDQ...于是就来发一发一道CDQ的练习题
看上去就是可以dp的样子。
设\(dp_{i}\)为以i结尾的最长不下降序列。
易得:\(dp_{i}\)=\(max(dp_{j})+1\)\((j<=i\)&&\(Max_{j}<=a_{i}\)&&\(a_{j}<=Min_{i})\)
\(Max_{i}\)和\(Min_{i}\)表示第i个点所有变化中的最大值和最小值。
我们考虑用一个什么东西来维护这个dp。
我的第一反应是树状数组套动态开点线段树,而且写那玩意应该也不会太长。
突然想到最近学了CDQ。
于是讲下CDQ怎么搞。
因为有两个两边不是同一个数组的条件,所以我们在solve的时候,要对\([l,mid]\)和\([mid+1,r]\)的根据不同的两个数组sort下,然后用个树状数组维护前缀max,算下左边对右边的贡献。
然后因为是dp,所以我们不能直接分治\([l,mid]\)和\([mid+1,r]\)然后合并,我们应该先分治\([l,mid]\)然后算好\([l,mid]\)对\([mid+1,r]\)的贡献,然后再去分治\([mid+1,r]\) (记得去做\([mid+1,r]\)前先把数组\([mid+1,r]\)恢复)
#include<cstdio>
#include<algorithm>
#include<string>
#define ll long long
#define For(i,x,y) for (register int i=(x);i<=(y);i++)
#define Dow(i,x,y) for (register int i=(x);i>=(y);i--)
#define cross(i,k) for (register int i=first[k];i;i=last[i])
using namespace std;
inline ll read(){
ll x=0;int ch=getchar(),f=1;
while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
if (ch=='-'){f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
inline ll min(ll a,ll b){return a<b?a:b;}
inline ll max(ll a,ll b){return a>b?a:b;}
const int N = 100010;
struct node{
int max,min,v,ans,id;
}a[N];
int n,m,x,y,ans,Max;
int c[N];
inline void Add(int x,int y){for (;x<=Max;x+=x&(-x)) c[x]=max(c[x],y);}
inline int Query(int x){int ans=0;for (;x;x-=x&(-x)) ans=max(ans,c[x]);return ans;}
inline void Clear(int x){for (;x<=Max;x+=x&(-x)) c[x]=0;}
inline bool cmp1(node a,node b){return a.max<b.max;}
inline bool cmp2(node a,node b){return a.v<b.v;}
inline bool cmp3(node a,node b){return a.id<b.id;}
inline void CDQ(int l,int r){
if (l==r) return;
int mid=l+r>>1;
CDQ(l,mid);
sort(a+l,a+mid+1,cmp1),sort(a+mid+1,a+r+1,cmp2);
int L=l,R=mid+1;
for (;L<=mid&&R<=r;R++){
for (;a[L].max<=a[R].v&&L<=mid;L++) Add(a[L].v,a[L].ans);
a[R].ans=max(a[R].ans,Query(a[R].min)+1);
}
For(i,R,r) a[i].ans=max(a[i].ans,Query(a[i].min)+1);
For(i,l,L) Clear(a[i].v);
sort(a+mid+1,a+r+1,cmp3);
CDQ(mid+1,r);
}
int main(){
n=read(),m=read();
For(i,1,n) a[i].v=a[i].max=a[i].min=read(),a[i].id=i;
For(i,1,m){
x=read(),y=read();
a[x].max=max(a[x].max,y),a[x].min=min(a[x].min,y);
}
For(i,1,n) Max=max(Max,max(a[i].v,a[i].min)),a[i].ans=1;
//For(i,1,n) printf("%d %d %d\n",a[i].v,a[i].min,a[i].max);puts("");
CDQ(1,n);
For(i,1,n) ans=max(ans,a[i].ans);
//For(i,1,n) printf("%d %d %d %d\n",a[i].v,a[i].min,a[i].max,a[i].ans);
printf("%d",ans);
}
Luogu P4093 [HEOI2016/TJOI2016]序列 dp套CDQ的更多相关文章
- 洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP
洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他. 玩具上有一个数列,数列中某些项的值可能会 ...
- 洛谷 P4093 [HEOI2016/TJOI2016]序列 解题报告
P4093 [HEOI2016/TJOI2016]序列 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一 ...
- 洛谷 P4093 [HEOI2016/TJOI2016]序列(Cdq+dp)
题面 luogu 题解 \(Cdq分治+dp\) \(mx[i],mn[i]\)分别表示第\(i\)位最大,最小能取到多少 那么有 \(j < i\) \(mx[j] \le a[i]\) \( ...
- BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j) if(a[ ...
- 洛谷P4093 [HEOI2016/TJOI2016]序列
题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所有变化的可能性, ...
- BZOJ4553/洛谷P4093 [HEOI2016/TJOI2016]序列 动态规划 分治
原文链接http://www.cnblogs.com/zhouzhendong/p/8672434.html 题目传送门 - BZOJ4553 题目传送门 - 洛谷P4093 题解 设$Li$表示第$ ...
- P4093 [HEOI2016/TJOI2016]序列
题目链接 题意分析 我们假设每一个数都有一个变动范围\([L_i,R_i]\) 那么我们令\(dp[i]\)表示以\(i\)结尾的最长不下降子序列的长度 那么就是\(dp[i]=max\{dp[j]+ ...
- cdq分治(hdu 5618 Jam's problem again[陌上花开]、CQOI 2011 动态逆序对、hdu 4742 Pinball Game、hdu 4456 Crowd、[HEOI2016/TJOI2016]序列、[NOI2007]货币兑换 )
hdu 5618 Jam's problem again #include <bits/stdc++.h> #define MAXN 100010 using namespace std; ...
- [Luogu P2824] [HEOI2016/TJOI2016]排序 (线段树+二分答案)
题面 传送门:https://www.luogu.org/problemnew/show/P2824 Solution 这题极其巧妙. 首先,如果直接做m次排序,显然会T得起飞. 注意一点:我们只需要 ...
随机推荐
- 基于 Docker 的 Zabbix 微服务系统
zabbix 官网提供一个镜像 [ zabbix-appliance ], 可以直接拉起一个 zabbix-server. 但是数据库无法分离出来. 本实践使用 zabbix 官方提供的 Docker ...
- bzoj 1483 链表启发式合并
首先我们可以比较容易的在n的时间内算出来开始的答案,我们维护一些链表,分别表示不同的颜色,那么我们在计算答案的时候,只需要扫一遍所有的链表,判断链表相邻两项是否在序列中相邻,不相邻的话肯定在这其中的一 ...
- linux进程管理-定时定期执行任务
0.计划任务的命令: at 安排作业在某一时刻执行 batch 安排作业在系统负载不重时执行 crontab 安排周期性运行的作业 1.at命令用法: 安排命令或者多个命令在指定的时间运行一次 语法 ...
- Linux 入门记录:十五、Linux 网络基本配置
一.以太网(Ethernet) 以太网(Ethernet)是一种计算机局域网技术.IEEE 组织的 IEEE 802.3 标准制定了以太网的技术标准,它规定了包括物理层的连线.电子信号和介质访问层协议 ...
- JSON对象与字符串之间的相互转换
<html> <head> <meta name="viewport" content="width=device-width" ...
- HDU 6188 Duizi and Shunzi 贪心
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6188 题意:给了n个数,然后现在问我们最多构成多少个对子和顺子,其中对子是2个相同的牌,顺子是3个连续 ...
- JDBC数据源连接池(1)---DBCP
何为数据源呢?也就是数据的来源.我在前面的一篇文章<JDBC原生数据库连接>中,采用了mysql数据库,数据来源于mysql,那么mysql就是一种数据源.在实际工作中,除了mysql,往 ...
- cf786a
title: CodeForces 786A Berzerk data: 2018-3-3 10:29:40 tags: 博弈论 bfs 无限 with draw copyright: true ca ...
- 【DUBBO】dubbo的Router接口
Router服务路由, 根据路由规则从多个Invoker中选出一个子集AbstractDirectory是所有目录服务实现的上层抽象, 它在list列举出所有invokers后,会在通过Router服 ...
- C语言实现二叉排序树
程序以'#'结尾的二叉排序树. /*(双重指针 BSTree *T)问:数据结构中 二叉树建立结点为什么用 双重指针?详细解释下双重指针 答:指针的指针.因为树的结点要用指针描述.如果只用指针,作形参 ...