cdq分治 提高篇
优化动态规划
序列
首先要会最长上升子序列的转移,这里就不说了。
我们 \(i\) 位置的初始值为 \(a_i\),可能变成的最大值为 \(mx_i\),可能变成的最小值为 \(mn_i\)。
然后如果 \(j\) 要转移到 \(i\),则需要满足:\(j<i,mx_j\le a_i,a_j\le mn_i\)。然后考虑把 \([l,mid]\) 按照 \(mx\) 排序,使得如果出现 \(j\) 满足 \(mx_j>a_i\) 那么 \([l,j-1]\) 是一个极大的区间满足这个区间的数全部满足前两个要求(因为 \(mx\) 单调不降)。还有就是,因为 \([mid+1,r]\) 按照 \(a\) 排序,所以可以保证如果对于区间 \([l,j]\) 的 \(mx\) 值全部不大于 \(i\) 的 \(a\) 值,那么对于 \(k>i\) 也不会出现 \(mx\) 值更大的情况,所以转移是对的。
然后就是怎么转移,大概就是把 \(j\) 的 \(f\) 值扔进树状数组,到转移的时候查一下 \(a\) 值不大于当前点 \(mn\) 值的点的最大 \(f\) 值进行转移(\(f\) 是动态规划转移数组)。
最后看一下代码:
#include<bits/stdc++.h>
#define int long long
#define N 100005
#define lim 100000
using namespace std;
int n,m,a[N],mx[N],mn[N],f[N],p[N],c[N];
bool cmp1(int x,int y){
return mx[x]<mx[y];
}
bool cmp2(int x,int y){
return a[x]<a[y];
}
int lowbit(int x){
return x&-x;
}
void modify(int x,int v){
while(x<=lim){
c[x]=max(c[x],v);
x+=lowbit(x);
}
}
int qry(int x){
int res=0;
while(x){
res=max(res,c[x]);
x-=lowbit(x);
}
return res;
}
void clear(int x){
while(x<=n){
c[x]=0;
x+=lowbit(x);
}
}
void cdq(int l,int r){
if(l==r){
f[l]=max(f[l],1ll);
return;
}
int mid=l+r>>1;
cdq(l,mid);
for(int i=l;i<=r;i++){
p[i]=i;
}
sort(p+l,p+mid+1,cmp1);
sort(p+mid+1,p+r+1,cmp2);
int j=l;
for(int i=mid+1;i<=r;i++){
while(j<=mid&&mx[p[j]]<=a[p[i]]){
modify(a[p[j]],f[p[j]]);
j++;
}
f[p[i]]=max(f[p[i]],qry(mn[p[i]])+1);
}
for(int i=l;i<=mid;i++){
clear(a[i]);
}
cdq(mid+1,r);
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
mx[i]=mn[i]=a[i];
}
while(m--){
int x,y;
cin>>x>>y;
mx[x]=max(mx[x],y);
mn[x]=min(mn[x],y);
}
cdq(1,n);
int res=0;
for(int i=1;i<=n;i++){
res=max(res,f[i]);
}
cout<<res;
return 0;
}
Cool loves touli
这个题和上面的一样非常套路。就是考虑离散化之后,对两边采取对应的关键字进行排序,然后就是按照最长上升子序列的方式进行转移,最后还原就做完了。
这里笔者有个经典错误,把在树状数组用到的后两维离散化了,没有注意到第二维比了大小,然后就一直 \(0\) 分。
代码:
#include<bits/stdc++.h>
#define int long long
#define N 300005
#define lim 300000
using namespace std;
int n,m,b[N],c[N],res;
struct node{
int l,s,w,a;
int f;
}a[N];
bool cmpl(node a,node b){
return a.l<b.l;
}
bool cmps(node a,node b){
return a.s<b.s;
}
bool cmpa(node a,node b){
return a.a<b.a;
}
int lowbit(int x){
return x&-x;
}
void modify(int x,int v){
while(x<=lim){
c[x]=max(c[x],v);
x+=lowbit(x);
}
}
int qry(int x){
int res=0;
while(x){
res=max(res,c[x]);
x-=lowbit(x);
}
return res;
}
void clear(int x){
while(x<=lim){
c[x]=0;
x+=lowbit(x);
}
}
void cdq(int l,int r){
if(l==r){
a[l].f=max(a[l].f,1ll);
return;
}
int mid=l+r>>1;
cdq(l,mid);
sort(a+l,a+mid+1,cmpa);
sort(a+mid+1,a+r+1,cmps);//事实上这里的关键字取决于while里比大小的两个变量
int i=l,j=mid+1;
while(j<=r){
while(i<=mid&&a[i].a<=a[j].s){//这里比了大小,所以后三维都要离散化
modify(a[i].w,a[i].f);
i++;
}
a[j].f=max(a[j].f,qry(a[j].a)+1);//正常转移
res=max(res,a[j].f);
j++;
}
for(j=l;j<i;j++)clear(a[j].w);
sort(a+mid+1,a+r+1,cmpl);//还原
cdq(mid+1,r);
}
signed main(){
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++){
cin>>a[i].l>>a[i].s>>a[i].w>>a[i].a;
b[++cnt]=a[i].s;
b[++cnt]=a[i].w;
b[++cnt]=a[i].a;
}
sort(b+1,b+cnt+1);
m=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<=n;i++){
a[i].s=lower_bound(b+1,b+m+1,a[i].s)-b;
a[i].w=lower_bound(b+1,b+m+1,a[i].w)-b;
a[i].a=lower_bound(b+1,b+m+1,a[i].a)-b;
}
sort(a+1,a+n+1,cmpl);
cdq(1,n);
cout<<res;
return 0;
}
cdq分治 提高篇的更多相关文章
- [luogu3157][bzoj3295][CQOI2011]动态逆序对【cdq分治+树状数组】
题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序 ...
- 一篇自己都看不懂的CDQ分治&整体二分学习笔记
作为一个永不咕咕咕的博主,我来更笔记辣qaq CDQ分治 CDQ分治的思想还是比较简单的.它的基本流程是: \(1.\)将所有修改操作和查询操作按照时间顺序并在一起,形成一段序列.显然,会影响查询操作 ...
- 【学术篇】bzoj3262 陌上花开. cdq分治入门
花儿们已经很累了-- 无论是花形.颜色.还是气味, 都不是为了给人们摆出来欣赏的, 更不是为了当做出题的素材的, 她们并不想自己这些属性被没有生命的数字量化, 并不想和其它的花攀比, 并无意分出个三六 ...
- CCF NOI Online 2021 提高组 T3 岛屿探险(CDQ 分治,Trie 树)
题面 凇睦是一个喜欢探险的女孩子,这天她到一片海域上来探险了. 在这片海域上一共有 n 座岛屿排成一排,标号为 1, 2, 3, . . . , n.每座岛屿有两个权值,分别为劳累度 ai 和有趣度 ...
- 【教程】简易CDQ分治教程&学习笔记
前言 辣鸡蒟蒻__stdcall终于会CDQ分治啦! CDQ分治是我们处理各类问题的重要武器.它的优势在于可以顶替复杂的高级数据结构,而且常数比较小:缺点在于必须离线操作. CDQ分治的基 ...
- bzoj3295: [Cqoi2011]动态逆序对(cdq分治)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- [学习笔记] CDQ分治 从感性理解到彻底晕菜
最近学了一种叫做CDQ分治的东西...用于离线处理一系列操作与查询似乎跑得很快233 CDQ的名称似乎源于金牌选手陈丹琦 概述: 对于一坨操作和询问,分成两半,单独处理左半边和处理左半边对于右半边的影 ...
- [用CDQ分治解决区间加&区间求和]【习作】
[前言] 作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢 于是,用CDQ分治解决区间加&区间求和这篇习作应运而生 [Par ...
- bzoj3963[WF2011]MachineWorks cdq分治+斜率优化dp
3963: [WF2011]MachineWorks Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 270 Solved: 80[Submit][S ...
- 天使玩偶:CDQ分治
这道好(du)题(liu)还是很不错的 挺锻炼代码能力和不断优化 卡常的能力的. 对于 每次询问 我都可以将其分出方向 然后 写 也就是针对于4个方向 左下 左上 右下 右上 这样的话 就成功转换了问 ...
随机推荐
- 关于编译告警 C4819 的完整解决方案 - The file contains a character that cannot be represented in the current code page (number). Save the file in Unicode format to prevent data loss.
引言 今天迁移开发环境的时候遇到一个问题,同样的操作系统和 Visual Studio 版本,原始开发环境一切正常,但是迁移后 VS 出现了 C4819 告警,上网查了中文的一些博客,大部分涵盖几种解 ...
- 聊一聊 Monitor.Wait 和 Pluse 的底层玩法
一:背景 1. 讲故事 在dump分析的过程中经常会看到很多线程卡在Monitor.Wait方法上,曾经也有不少人问我为什么用 !syncblk 看不到 Monitor.Wait 上的锁信息,刚好昨天 ...
- docker 单机部署redis集群
docker 部署redis集群 1.创建redis网卡 docker network create redis --subnet 172.38.0.0/16 查看网卡信息 docker networ ...
- windows系统安装或使用inspect.exe工具
确认是否安装? 结合工具everything,进行搜索 选择对应操作系统的版本,右键->选择打开路径,进到inspect.exe的安装路径,双击打开软件 软件开启后,就会自动开始抓取目前软件界面 ...
- python之集合学习
*******************集合{set}******************* 1.集合set 可变 特点:是由不同元素组成 是无序的 集合中元素必须是不可变类型例如(字符串/元祖/数字) ...
- Meilisearch 安装和使用教程
如今搜索功能已成为几乎所有应用不可或缺的一部分.无论是电商平台.内容管理系统,还是企业内部知识库,用户都期待能够快速.准确地找到他们需要的信息.然而,传统的搜索解决方案往往面临着诸多挑战:响应速度慢. ...
- 【基础计算】ESDF栅格距离图计算并行加速版
前言与参考 这一部分仅为路径规划源码及论文GPIR的一个小部分,但是有代码实现,第一次看的时候有些懵,所以特此记录:主要是设置好了栅格地图后,添加了障碍物后,对其的欧式距离计算和梯度计算等.原代码中为 ...
- Excel好用的技巧
http://www.360doc.com/content/18/0603/07/39124342_759238510.shtml
- FFmpeg开发笔记(三十六)Linux环境安装SRS实现视频直播推流
<FFmpeg开发实战:从零基础到短视频上线>一书在第10章介绍了轻量级流媒体服务器MediaMTX,通过该工具可以测试RTSP/RTMP等流媒体协议的推拉流.不过MediaMTX的功能 ...
- 痞子衡嵌入式:浅聊恩智浦i.MXRT官方SDK里关于串行Flash相关的驱动与例程资源(上篇)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MXRT官方SDK里关于串行Flash相关的驱动与例程资源. 经常有同事以及 i.MXRT 客户咨询痞子衡,咱们恩智浦官方 S ...