CDQ&整体二分-三维偏序(陌上花开)
题面
本文讲cdq,整体二分的思路与做法。=分治VS数据结构
其实维度这一方面,空间几何可以是维度,像时间这样有规定顺序的词语也可能是维度。
cdq
三维偏序,一般可以用一维一维的消。可以用cdq嵌套,线段树嵌套来做,我还不会,这里用排序一维,cdq一维,树状数组一维,感觉对比嵌套在思维拓展方面有帮助。
题面的\(f[i]\)满足\(a[j]\leq a[i],b[j]\leq b[i],c[j]\leq c[i]\),因为元素相同的情况在分治中会出现漏解,所以cdq分治在出现相同元素时常做去重处理。
做法:
先按去重后序列以a为第一关键字 注意不是唯一关键字 排序,
然后常规分治,之后将左右区间分别按照b为(第一)关键字排序,
这时因为我们要根据左区间给右区间贡献,而左区间的a值一定都小于右区间的a值,所以a无影响。按照b归并排序的同时更新树状数组,并得到右区间的贡献最后记得清空树状数组
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#define M (l+r>>1)
using namespace std;
const int N=1e5+5;
int n,k,tot,ans[N],tr[N<<1];
struct qh{
int a,b,c,ans,cnt;
}in[N],a[N];
bool c1(qh a,qh b){return a.a==b.a?a.b==b.b?a.c<b.c:a.b<b.b:a.a<b.a;}
bool c2(qh a,qh b){return a.b==b.b?a.c<b.c:a.b<b.b;}
int lowbit(int x){return x&(-x);}
void add(int x,int y){for(int i=x;i<=k;i+=lowbit(i)) tr[i]+=y;return ;}
int gs(int x){int res=0;for(int i=x;i;i-=lowbit(i)) res+=tr[i];return res;}
void cdq(int l,int r){
if(l==r) return ;
cdq(l,M);cdq(M+1,r);
sort(a+l,a+M+1,c2);sort(a+M+1,a+r+1,c2);
int q1=l,q2=M+1;
while (q1<=M&&q2<=r){
if(a[q1].b<=a[q2].b){
add(a[q1].c,a[q1].cnt);
q1++;
}
else{
a[q2].ans+=gs(a[q2].c);
q2++;
}
}
while (q2<=r){
a[q2].ans+=gs(a[q2].c);
q2++;
}
for(int i=l;i<q1;i++) add(a[i].c,-a[i].cnt); //*******
return ;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d%d%d",&in[i].a,&in[i].b,&in[i].c);
sort(in+1,in+n+1,c1);
int c=0;
for(int i=1;i<=n;i++){
c++;
if(in[i].a!=in[i+1].a||in[i].b!=in[i+1].b||in[i].c!=in[i+1].c) a[++tot]=(qh){in[i].a,in[i].b,in[i].c,0,c},c=0;
}
cdq(1,tot);
for(int i=1;i<=tot;i++) ans[a[i].ans+a[i].cnt-1]+=a[i].cnt;
for(int i=0;i<n;i++) printf("%d\n",ans[i]);
return 0;
}
//cdq分治:相同元素做去重处理
整体二分
题目大意:
给定一个长度为 n ( n <= 50,000 ) 的数组 a[1] , a[2] ... a[n] 和 q ( q <= 10,000 ) 此询问,每次询问:
Q i j k 表示区间 [i,j] 中第 k 小的数是多少,并输出这个数
C i t 表示将第 i 个数改为 t
样例输入
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
样例输出
3
6
整体二分,顾名思义,就是把所有的东西拿来一起二分。在这道题里我们还要开一棵树状数组。
- 修改操作等于删除+添加
- 查询操作=二分答案
- 修改和加入按照所在位置二分
- 顺序处理所有操作
如果哪一步不懂就看代码吧。
#include<cstdio>
#include<iostream>
#define M (l+r>>1)
using namespace std;
const int N=5e4+5;
int n,q,tot,qtot,a[N],ans[N],tr[N],cnt[N<<1];
struct qh{
int x,y,z,t,ad,s;
}E[N<<1],El[N<<1],Er[N<<1],op;
inline int Rd(){
int s=0,w=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while (ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int y){
for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=y;
return ;
}
inline int gs(int x){
int res=0;
for(int i=x;i;i-=lowbit(i)) res+=tr[i];
return res;
}
inline void init(int h,int t,int l,int r){
if(h>t) return ;
if(l==r){ //pd l==r
for(int i=h;i<=t;i++) if(E[i].t==3) ans[E[i].ad]=l;
return ;
}
for(int i=h;i<=t;i++){ //ls
if(E[i].t==1&&E[i].y<=M) add(E[i].x,1);
else if(E[i].t==2&&E[i].y<=M) add(E[i].x,-1);
else if(E[i].t==3) cnt[i]=gs(E[i].y)-gs(E[i].x-1);
}
for(int i=h;i<=t;i++){ //empty
if(E[i].t==1&&E[i].y<=M) add(E[i].x,-1);
else if(E[i].t==2&&E[i].y<=M) add(E[i].x,1);
}
int l1=0,r1=0;
for(int i=h;i<=t;i++){ //merge
if(E[i].t==3){
if(E[i].s+cnt[i]>=E[i].z) El[l1++]=E[i];
else E[i].s+=cnt[i],Er[r1++]=E[i];
}
else if(E[i].y<=M) El[l1++]=E[i];
else Er[r1++]=E[i];
}
for(int i=0;i<l1;i++) E[h+i]=El[i];
for(int i=0;i<r1;i++) E[h+l1+i]=Er[i];
init(h,h+l1-1,l,M);
init(h+l1,t,M+1,r);
}
int main(){
n=Rd();q=Rd();
for(int i=1;i<=n;i++){
a[i]=Rd();
op.x=i;op.y=a[i];op.t=1;
E[++tot]=op;
}
while (q--){
char ch=getchar();
int x,y,z;
while (ch!='Q'&&ch!='C') ch=getchar();
if(ch=='Q'){
x=Rd();y=Rd();z=Rd();
op.x=x;op.y=y;op.z=z;op.t=3;op.ad=++qtot;
E[++tot]=op;
}
else{
x=Rd();y=Rd();
op.x=x;op.y=a[x];op.t=2;E[++tot]=op;
op.x=x;op.y=y;op.t=1;E[++tot]=op;
a[x]=y;
}
}
init(0,tot,0,1e9);
for(int i=1;i<=qtot;i++) printf("%d\n",ans[i]);
return 0;
}
结构跟权值线段树还挺像
总结
整体二分的 思想 是同时对处理区间和答案进行二分。
CDQ分治的 **思想 **是用处理方式(关键字)进行排序,然后对时间进行二分。
整体二分 可以用于 求询问操作一样,而且可以二分答案解决的问题(具有单调性,如时间可以二分)。
CDQ分治 可以用于 求多维偏序问题。
整体二分从上往下做,CDQ分治从下往上做。
两种分治算法都比较暴力,它们的优点是代码短而清晰,缺点是复杂度玄学,必须离线。
所以,这次还是没能决出胜负啊。
CDQ&整体二分-三维偏序(陌上花开)的更多相关文章
- 并不对劲的cdq分治解三维偏序
为了反驳隔壁很对劲的太刀流,并不对劲的片手流决定与之针锋相对,先一步发表cdq分治解三维偏序. 很对劲的太刀流在这里-> 参照一.二维偏序的方法,会发现一位偏序就是直接排序,可以看成通过排序使 ...
- bzoj 1146 网络管理Network (CDQ 整体二分 + 树刨)
题目传送门 题意:求树上路径可修改的第k大值是多少. 题解:CDQ整体二分+树刨. 每一个位置上的数都会有一段持续区间 根据CDQ拆的思维,可以将这个数拆成出现的时间点和消失的时间点. 然后通过整体二 ...
- cdq分治解决三维偏序
问题背景 在三维坐标系中有n个点,坐标为(xi,yi,zi). 定义一个点A比一个点B小,当且仅当xA<=xB,yA<=yB,zA<=zB.问对于每个点,有多少个点比它小.(n< ...
- CDQ解决一些三维偏序的问题
本来几天前就该记录的东西,硬生生被我拖到了现在,太懒了... 在cdq学习时,二维偏序已经解决了,无非就是先sort使第一维有序,然后再用cdq或者数据结构处理第二维.而三维偏序的时候呢,大佬的做法好 ...
- 【算法学习】【洛谷】cdq分治 & P3810 三维偏序
cdq是何许人也?请参看这篇:https://wenku.baidu.com/view/3b913556fd0a79563d1e7245.html. 在这篇论文中,cdq提出了对修改/询问型问题(Mo ...
- BZOJ 3262: 陌上花开 (cdq分治,三维偏序)
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std; c ...
- hdu5618(cdq分治求三维偏序)
题意:给n(n<=100000)个点,坐标为(xi,yi,zi)(1<=xi,yi,zi<=100000),定义一个点A比一个点B小,当且仅当xA<=xB,yA<=yB, ...
- SPOJ:Another Longest Increasing Subsequence Problem(CDQ分治求三维偏序)
Given a sequence of N pairs of integers, find the length of the longest increasing subsequence of it ...
- CDQ分治与整体二分小结
前言 这是一波强行总结. 下面是一波瞎比比. 这几天做了几道CDQ/整体二分,感觉自己做题速度好慢啊. 很多很显然的东西都看不出来 分治分不出来 打不出来 调不对 上午下午晚上的效率完全不一样啊. 完 ...
- CDQ分治&整体二分学习个人小结
目录 小结 CDQ分治 二维LIS 第一道裸题 bzoj1176 Mokia bzoj3262 陌上花开 bzoj 1790 矩形藏宝地 hdu5126四维偏序 P3157 [CQOI2011]动态逆 ...
随机推荐
- 【Mybatis】05 官方文档指北阅读 vol3 配置 其二
对象工厂(objectFactory)[省略,入门阶段实在不懂] 插件(plugins)[省略,入门阶段实在不懂] 环境配置(environments) MyBatis 可以配置成适应多种环境,这种机 ...
- 【SpringBoot】Re 02 Import与自定义装配实现
Import的注册形式: 1.使用@Import导入一个或者多个类字节对象 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME ...
- Python报错:pkg-config could not find libraries ['avformat', 'avcodec', 'avdevice', 'avutil', 'avfilter', 'swscale', 'swresample']
参考: https://github.com/PyAV-Org/PyAV/issues/238 https://pyav.org/docs/6.1.2/installation.html#mac-os ...
- CPU端多进程/多线程调用CUDA是否可以加速???
相关: NVIDIA显卡cuda的多进程服务--MPS(Multi-Process Service) tensorflow1.x--如何在C++多线程中调用同一个session会话 tensorflo ...
- Python示例——负数的位运算
平时在coding的时候虽然会遇到位运算但一般也都是正数的位运算,今天突然见到了使用负数的位运算,对此十分好奇和困惑,为此做了下了解,于是有了此文. 给出一些位运算的例子: 其中,正数的位运算是最为常 ...
- 被怼了:acks=all消息也会丢失?
消息队列是面试中一定会被问到的技术模块,虽然它在面试题占比不及并发编程和数据库,但也属于面试中的关键性问题.所以今天我们就来看一道,MQ 中高频,但可能会打破你以往认知的一道面试题. 所谓的关键问题指 ...
- 为啥动态显示的名字就显示了undefined?
看不懂了昂,记录一下,慢慢理解吧 <!DOCTYPE html> <html> <head> <meta charset="utf-8"& ...
- Unity编辑器批量设置图片格式
在游戏开发中,经常需要批量设置图片的格式为Sprite类型,手动设置太麻烦,下面的编辑器脚本实现选中文件夹右键/Texture/SetAllImagesToSpriteType实现批量设置图片格式,具 ...
- springboot之banner.txt
在springboot启动过程中,我们经常可以看到控制台打印下面图文: 实际上这个打印图文,是可以自定义的,可以在springboot的resource中创建一个banner.txt文件,在启动时就会 ...
- 【CMake系列】10-cmake测试集成googletest与第三方库自动化构建
cmake测试,使用ctest 可能不能满足我们的需求,需要我们使用更为强大的第三方测试框架,如googletest,完成项目中的测试工作 本篇文章将第三方测试框架 googletest,引入,同时也 ...