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个方向 左下 左上 右下 右上 这样的话 就成功转换了问 ...
随机推荐
- Mysql慢sql优化
Mysql慢sql优化 index1.MySQL的执行过程2.索引的定义3.MySQL执行计划explain or desc4.索引使用/创建规则5.弊端6.设计规范7.SQL建议 1. MySQL ...
- 《软件性能测试分析与调优实践之路》第二版-手稿节选-Mysql数据库性能定位与分析
在做MySQL数据的性能定位前,需要先知道MySQL查询时数据库内部的执行过程.只有弄清SQL的执行过程,才能对执行过程中的每一步的性能做定位分析.如图6-2-1所示. 图6-2-1 从图中可以看到, ...
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Map Kit(2)
1.问题描述: 能否设置点击地图,地图标记上的文字不消失? 解决方案: 你好,这个功能设计本身就是点击屏幕marker的信息窗消失:如果用户只是想信息窗中的文字一直展示,可以不用信息窗实现 ,建议可以 ...
- 如何从零开始集成DTM Android SDK
什么是动态标签管理? 动态标签管理(Dynamic Tag Manager,简称"DTM"),可让开发者快速配置更新测量代码及相关代码片段,可以基于Web界面轻松地进行分析.测量代 ...
- 在linux系统中,对标准输出(stdout,文件描述符为 1)和标准错误(stderr,文件描述符为 2)重定向到文件
请参考:2>/dev/null和>/dev/null 2>&1和2>&1>/dev/null的区别 下面的是本人浅尝辄止了,并非全貌,还是上面的文章说的比 ...
- 运行前端React框架出现node Error: bind EADDRINUSE null的解决方法
运行前端React代码时,出现这样的错误: node Error: bind EADDRINUSE null 后来发现端口号冲突,换个端口号后问题就可以解决了.
- vue小知识:多层数据双向相应之向上派发和向下派发($dispatch和$broadcast)
注意:这两个实例已经在vue3中弃用啦!!!(所以不详细说了,封装知道怎么用就行了,作为了解) 都是在vue实例配置(main.js) 向上派发:$dispatch 注意,在相应后代组件中使用 thi ...
- vscode 调试 nodejs 程序
nodejs 服务在vscode 中的调试 1.安装vscode 略(这不用说了吧) 2.写一个能跑的nodejs 程序 其实看到这个,自己已经有一个能跑的nodejs 程序,不用看我的了 我这里是我 ...
- odoo 给form表单视图内联列表添加按钮
实践环境 Odoo 14.0-20221212 (Community Edition) 代码实现 模块文件组织结构 说明:为了更好的表达本文主题,一些和主题无关的文件.代码已略去 odoo14\cus ...
- 使用with 还是 join
用分解关联查询的方式查询具有以下优势:多次单表查询,让缓存的效率更高:许多应用程序可以方便地缓存单表查询对应的结果对象.对 MYSQL 的查询缓存来说,如果关联中的某个表发生了变化,那么就无法使用查询 ...