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]动态逆 ...
随机推荐
- 【Hibernate】Re04 JPA规范使用
都忘了前面一些小前提,就是数据库需要是存在的,不过写链接参数都会写上的 JPA实现就是和Hibernate类似,也需要对应的配置文件等等... 1.配置文件必须命名[persistence.xml]且 ...
- 强化学习中的“sample efficiency”应该如何翻译 —— “样本效率”还是“采样效率”
问题: 强化学习中的"sample efficiency"应该如何翻译 -- "样本效率"还是"采样效率" 答案: 具体看上下文内容.如果是 ...
- OneFlow是否真的实现了单机代码无侵害的运行在分布式集群上?
答案: 不是,但也是. 严格意义上来说,不是. 因为技术OneFlow的代码,要从单机改到分布式,也需要改配置,需要给所有的变量设置具体的全局存储还是局部存储,如果局部存储又应该如何划分,等等,这些其 ...
- 使用UltraISO克隆clone树莓派SD卡(注意不是复制、备份,是克隆)
搞了好长时间做了一个树莓派的SD卡,包括了一些自己安装的配置,为了防止哪天把这个SD卡搞坏掉(比如写数据时候断电,比如apt upgrade时掉电),于是考虑把这个SD卡进行克隆clone. 因为手上 ...
- 使用pybind11为Python编写一个简单的C语言扩展模块
相关: 为Python编写一个简单的C语言扩展模块 在Pybind11 出现之前为Python编写扩展模块的方法有多种,但是并没有哪种方法被认为一定比其他的好,因此也就变得在为Python编写扩展模块 ...
- SMU Spring 2023 Contest Round 5(2023 (ICPC) Jiangxi Provincial Contest -- Official Contest)
题目链接 Problem A. Drill Wood to Make Fire S * V >= n即可 #include<bits/stdc++.h> #define int lo ...
- AvaloniaChat—从源码构建指南
AvaloniaChat介绍 一个使用大型语言模型进行翻译的简单应用. 我自己的主要使用场景 在看英文文献的过程中,比较喜欢对照着翻译看,因此希望一边是英文一边是中文,虽然某些软件已经自带了翻译功能, ...
- Spring Boot 框架中配置文件 application.properties 当中的所有配置大全
Spring Boot 框架中配置文件 application.properties 当中的所有配置大全 #SPRING CONFIG(ConfigFileApplicationListener) s ...
- Python 字符串格式化输出
数字 n: int = 1000000000 print(f'{n:_}') # 1_000_000_000 print(f'{n:,}') # 1,000,000,000 对齐 var: str = ...
- 使用Pandas和NumPy实现数据获取
公众号本文地址:https://mp.weixin.qq.com/s/Uc4sUwhjLTpOo85ubj0-QA 以某城市地铁数据为例,通过提取每个站三个月15分钟粒度的上下客量数据,展示Panda ...