偏序问题及CDQ分治详解
CDQ用来解决分治时左半部分对右半部分造成影响的问题。
CDQ分治的经典问题是三维偏序问题。
要想解决三维偏序问题,首先你要知道什么是偏序。(废话)
一维偏序:
给出直线上的n个点,问有多少对点满足xi<=xj
对于这个问题,直接排序就可以了。
二维偏序:
给定平面内的n个点,问有多少对点满足xi<=xj且yi<=yj
这是个经典的树状数组问题,相信学过树状数组的人一定都做过·一道叫做数星星的题,这道题就是经典的二维偏序问题,并不需要二维数组,我们可以通过按x坐标为第一关键字排序,从而消除x坐标给答案带来的影响。然后我们用一个树状数组维护前缀和,记录之前有多少点的y坐标比该点小,由于在之前的x坐标一定比较小,因此只要保证y坐标即可。
三维偏序:
给出空间内的n个点,问有多少点对满足xi<=xj且yi<=yj且zi<=zj
树套树???码量++,空间++
在不强制在线的情况下,我们完全可以使用CDQ分治这种东西来简化一层树结构,因此三维偏序问题实际上可以这样处理:
1)仿照二位偏序问题,先给x排序,消除其影响。
2)使用CDQ分治,消除y的影响
3)使用数组维护z的前缀,统计答案。
1)、3)都是二维偏序的正常步骤,下面重点来讲讲CDQ分治
前边已经讲过了,CDQ分治要处理左区间对右区间的贡献问题。
其实很简单,我们把每一步操作分成三步:
1)递归处理左区间;2)递归处理右区间;3)处理左区间对右区间的贡献。
在三维偏序问题中,之所以不考虑右区间对左区间的贡献,是因为按x排序了,因此右区间一定不会对左区间造成贡献。
然后我们直接就按y排序,然后看一个东西是在左区间还是右区间,是左区间就放进一个树状数组中,否则直接求贡献。
因为CDQ直接分治到最小的单位,也就是一个点,因此可以保证所有答案都是没有遗漏的。
为了保证答案的不重复性,我们可以在求完贡献后把树状数组内贡献再撤消;
例题:洛谷P3810:陌上花开
参考代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#define N 500005
#define lowbit(x) x&-x
using namespace std;
int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ch^);ch=getchar();}
return x*f;
}
struct node{int x,y,z,id;}a[N];
bool cmpa(node a,node b)
{
if(a.x!=b.x)return a.x<b.x;
if(a.y!=b.y)return a.y<b.y;
return a.z<b.z;
}
bool cmpb(node a,node b)
{
if(a.y!=b.y)return a.y<b.y;
if(a.x!=b.x)return a.x<b.x;
return a.z<b.z;
}
int n,k,tot,c[],b[],f[],s,j,block[];
void modify(int x,int m){for(;x<=k;x+=lowbit(x))c[x]+=m;}
int query(int x){int res=;for(;x;x-=lowbit(x))res+=c[x];return res;}
void cdq(int l,int r)
{
if(l==r)return;
int mid=(l+r)/;
cdq(l,mid);cdq(mid+,r);
sort(a+l,a+r+,cmpb);
for(int i=l;i<=r;i++)(a[i].x<=mid)?modify(a[i].z,),s=:b[a[i].id]+=query(a[i].z);
for(int i=l;i<=r;i++)if(a[i].x<=mid)modify(a[i].z,-);
}
int main()
{
ios::sync_with_stdio();cin.tie();cout.tie();
cin>>n>>k;//n=read();k=read();
for(int i=;i<=n;i++)
{
cin>>a[i].x>>a[i].y>>a[i].z;//=read();a[i].y=read();a[i].z=read();
a[i].id=i;
}
sort(a+,a++n,cmpa);
for(int i=;i<=n;)
{
j=i+;
while(j<=n&&a[i].x==a[j].x&&a[i].y==a[j].y&&a[i].z==a[j].z)j++;
while(i<j)block[a[i].id]=a[j-].id,i++;
}
for(int i=;i<=n;i++)a[i].x=i;
cdq(,n);
for(int i=;i<=n;i++)f[b[block[a[i].id]]]++;
for(int i=;i<n;i++)printf("%d\n",f[i]);
return ;
}
三位偏序模板代码
偏序问题及CDQ分治详解的更多相关文章
- BZOJ3262陌上花开(三维偏序问题(CDQ分治+树状数组))+CDQ分治基本思想
emmmm我能怎么说呢 CDQ分治显然我没法写一篇完整的优秀的博客,因为我自己还不是很明白... 因为这玩意的思想实在是太短了: fateice如是说道: 如果说对于一道题目的离线操作,假设有n个操作 ...
- 陌上花开(三维偏序)(cdq分治)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3262 其实就是三位偏序的模板,cdq分治入门题. 学习cdq分治请看__stdcall大 ...
- cdq分治略解
前言 陌上花开,可缓缓归矣 --吴越王 寓意:意思是:田间阡陌上的花开了,你可以一边赏花,一边慢慢回来. 隐意:春天都到了,你怎么还没有回来.形容吴越王 ...
- 【CJOJ2375】 【HZOI 2015】偏序 II(cdq分治,树状数组)
传送门 CJOJ Solution 具体实现参考上一篇Blog(四维偏序) 代码实现1(cdq+cdq+cdq+BIT) /* mail: mleautomaton@foxmail.com autho ...
- 【CJOJ2616】 【HZOI 2016】偏序 I(cdq分治,树状数组)
传送门 CJOJ Solution 考虑这是一个四维偏序对吧. 直接cdq套在一起,然后这题有两种实现方法(树状数组的更快!) 代码实现1(cdq+cdq+cdq) /* mail: mleautom ...
- 分治法:三维偏序问题之CDQ分治
我怀疑那个k是用来定界限用的 #include <cstdio> #include <cstring> #include <algorithm> using nam ...
- 『cdq分治和多维偏序问题』
更新了三维偏序问题的拓展 cdq分治 \(cdq\)分治是一种由\(IOI\ Au\)选手\(cdq\)提出的离线分治算法,又称基于时间的分治算法. 二维偏序问题 这是\(cdq\)分治最早提出的时候 ...
- 【BZOJ2141】排队(CDQ分治)
[BZOJ2141]排队(CDQ分治) 题面 题面以及树套树做法见这里 题解 大部分树套树/主席树这类题目都可以用整体二分/CDQ分治来做. 这题考虑一下,在不考虑修改的情况下 贡献是如何产生的? 我 ...
- 并不对劲的cdq分治解三维偏序
为了反驳隔壁很对劲的太刀流,并不对劲的片手流决定与之针锋相对,先一步发表cdq分治解三维偏序. 很对劲的太刀流在这里-> 参照一.二维偏序的方法,会发现一位偏序就是直接排序,可以看成通过排序使 ...
随机推荐
- NTC电阻Rt与温度T关系
NTC电阻Rt与温度T公式如下: Rt=10000*exp(3950*(1/(273.15+T)-1/(273.15+25))). 例:0摄氏度时,电阻为33620.6037214357 欧姆 Rt= ...
- 过滤函数filter
>>> def validate(usernames): if (len(usernames) > 4) and (len(usernames) < 12): retur ...
- 关于本地使用antd的upload组件上传文件,ngnix报错405的问题
使用阿里的ui框架antd的upload,会自动请求ngnix上面的一个路径,也就是action所在的位置,一直报错405 not allowed,后来经讨论,统一将action写成一个路径,后端对这 ...
- layui下拉框右边图标动画,不要动画
/* 取消动画 / .layui-form-selected .layui-edge { margin-top: -3px; -webkit-transform: rotate(0deg); tran ...
- springboot2.0+mysql整合mybatis,发现查询出来的时间比数据库datetime值快了8小时
参考:https://blog.csdn.net/lx12345_/article/details/82020858 修改后查询数据正常
- linux运维、架构之路-KVM虚拟化技术
一.云计算概述 云计算:是一种资源使用和交付模式 虚拟化:一种具体的技术,用来将物理机虚拟成为多个相互独立的虚拟机.云计算不等于虚拟化,云计算是使用了虚拟化的技术做支撑 二.KVM配置使用 1.系统环 ...
- JS中的执行机制(setTimeout、setInterval、promise、宏任务、微任务)
1.执行机制 JS 是单线程的,处理 JS 任务(程序)只能一个一个顺序执行,所以 JS 中就把任务分为了同步任务和异步任务.同步的进入主线程先执行,异步的进入Event Table并注册函数,当指定 ...
- Java——容器(Auto-boxing/unboxing)
[打包/解包] 在Map中需要增加一个数值时,需要new一个对象出来,输出后又得进行强制类型转换,这就造成不便.在JDK1.5中使用Map接口提供了一种新的机制. 在合适的时机自动打包/解包(在J ...
- kohana学习经验
1.sql查询文件缓存使用 $tokens = DB::select('id', 'token') ->from('member') ->where('id', 'in', $users) ...
- 使用java操作elasticsearch之与es简历连接
Elasticsearch 的 Java 客户端非常强大:它可以建立一个嵌入式实例并在必要时运行管理任务. 运行一个 Java 应用程序和 Elasticsearch 时,有两种操作模式可供使用.该应 ...