三维偏序---cdq分治

  • cdq分治概述
  • 二维偏序概述
    • 二维偏序例题分析
  • 三维偏序概述
    • 例题分析

cdq分治概述

前置知识:(如果不懂要先去了解分治)
> 分治:
>     分而治之,将原问题不断划分为若干个子问题,
>     直到子问题规模足够小可以直接解决子问题间互相独立且与原问题形式相同,
>     递归求解这些子问题,然后将各子问题的解合并得到原问题的解

cdq 分治和dp一样,是一种思想,因此 cdq 分治涵盖的范围相当的广泛,由于这样的思路最早是被陈丹琦引入国内的,所以就叫 cdq 分治了。
cdq分治可解决的问题大致可分为三类:

  • 与点对有关的问题(三维偏序)
  • cdq 分治优化 1D/1D 动态规划的转移(还不懂 )
  • 通过 cdq 分治,将一些动态问题转化为静态问题

本篇博客主要介绍和总结用cqd分治解决的三维偏序问题

二维偏序概述

三维偏序,听起来似乎是个排序,三维偏序是在二维偏序的基础上进行的。
好了,那 二维偏序又是个啥??
二维偏序
给你一个长度为n的序列,每个序列都有a,b两种属性,让你求具有某些关系的点对(i,j)个数。一般思路是先确定一维的顺序,在此基础上用树状数组维护第二维。

二维偏序例题分析

hdu1541-----> 戳戳

Problem Description
Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given star. Astronomers want to know the distribution of the levels of the stars.

For example, look at the map shown on the figure above. Level of the star number 5 is equal to 3 (it’s formed by three stars with a numbers 1, 2 and 4). And the levels of the stars numbered by 2 and 4 are 1. At this map there are only one star of the level 0, two stars of the level 1, one star of the level 2, and one star of the level 3.

You are to write a program that will count the amounts of the stars of each level on a given map.

Input
The first line of the input file contains a number of stars N (1<=N<=15000). The following N lines describe coordinates of stars (two integers X and Y per line separated by a space, 0<=X,Y<=32000). There can be only one star at one point of the plane. Stars are listed in ascending order of Y coordinate. Stars with equal Y coordinates are listed in ascending order of X coordinate.

Output
The output should contain N lines, one number per line. The first line contains amount of stars of the level 0, the second does amount of stars of the level 1 and so on, the last line contains amount of stars of the level N-1.

Sample Input

5
1 1
5 1
7 1
3 3
5 5

Sample Output

1
2
1
1
0

题意:有n个星星,输入时是以从下到上,从左到右的方式输入(x,y)的值。每个星星左下方有多少个星星就评多少等级,也就是求对于每个星星 i,有多少个 j 满足 xi<xj , yi<yj 。

首先我们可以按照 x 坐标排序,发现对于 i 来说 大于 i 的点已经不在答案的贡献里了。那么答案就是在排序后的数组中找 1∼i-1有几个元素 y 比 yi 小。
那么我们直接树状数组即可。

#include <bits/stdc++.h>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int maxn=100000+10;
int n,c[maxn],ans[maxn];
struct Stars{int x,y;
}a[maxn];bool cmp(Stars a,Stars b){if(a.x!=b.x) return a.x<b.x;return a.y<b.y;
}inline int read(){register int x=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}return (f==1)?x:-x;
}
void add(int x,int y){for(;x<maxn;x+=lowbit(x)) c[x]+=y;
}
int sum(int x){int ans=0;for(;x;x-=lowbit(x)) ans+=c[x];return ans;
}int main()
{n=read();for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();sort(a+1,a+n+1,cmp);int now;for(int i=1;i<=n;i++){now=sum(a[i].y+1);ans[now]++;add(a[i].y+1,1);}for(int i=0;i<n;i++) printf('%d\n',ans[i]);return 0;
}

三维偏序概述

三维偏序
三维偏序就是在二维偏序的基础上加上一维。
给你一个长度为n的序列,每个序列都有a,b,c三种属性,让你求具有某些关系的点对(i,j)个数。一般思路是先确定一维的顺序,分治维护第二维,再结合上边的二维偏序中的树状数组维护第三维。

  1. 找到这个序列的中点 mid
  2. 将所有点对(i,j)划分为 3 类
    第一类是1<= i<=mid,1<= j<=mid
    第二类是1<=i<=mid,mid+1<=j<=n
    第三类是mid+1<=i<=n,mid+1<=j<=n
  3. 将 这个序列拆成两个序列(1,mid)和 (mid+1,n) 会发现第一类点对和第三类点对都在这两个序列之中,递归的去解决这两类点对
  4. 通过一些神奇的操作 (分治)方法来解决第二类点对

例题分析


输入数据

10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1

输出数据

3
1
3
0
1
0
1
0
0
1

先按x排序。分治时每次将前半边、后半边分别按y排序。虽然现在x的顺序被打乱了,但是前半边还是都小于后半边的,所以要是只计算前半边对后半边的偏序关系,是不会受到x的影响的。维护后一半的指针i,前一半的指针j,每次将i后移一位时,若y[j]<=y[i]则不断后移j,并不断将z[j]加入树状数组。然后再查询树状数组中有多少数小于等于z[i]。 最后要清空树状数组。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
const int maxm = 200005;
int n, m, kk;
int sum[maxm], p[maxm];
int lowbit(int x){ return x & (-x); }
void update(int x,int k){ for (int i = x; i <= kk; i+=lowbit(i)) sum[i] += k; }
int q(int x){ int ans = 0; for (int i = x; i != 0; i-=lowbit(i)) ans += sum[i]; return ans; }struct node{int x, y, z, w, ans;
} a[maxn], b[maxn];
bool rulex(node x,node y)
{if(x.x==y.x){if(x.y==y.y)return x.z < y.z;return x.y < y.y;}return x.x < y.x;
}
bool ruley(node x,node y)
{if(x.y==y.y)return x.z < y.z;return x.y < y.y;
}void slove(int l,int r)
{if(l==r)return;int mid = (l + r) / 2;int i = l, j = mid + 1;slove(l, mid);slove(mid + 1, r);sort(a + l, a + mid + 1, ruley);sort(a + mid + 1, a + r + 1, ruley);while(j<=r){while(a[j].y>=a[i].y&&i<=mid)update(a[i].z, a[i].w), i++;a[j].ans += q(a[j].z);j++;}for (j = l; j < i; j++)update(a[j].z, -a[j].w);
}int main()
{scanf("%d%d", &m, &kk);for (int i = 1; i <= m; i++)scanf("%d%d%d", &b[i].x, &b[i].y, &b[i].z);sort(b + 1, b + 1 + m, rulex);int cnt = 0, n = 0;for (int i = 1; i <= m; i++){cnt++;if(b[i].x!=b[i+1].x||b[i].y!=b[i+1].y||b[i].z!=b[i+1].z)a[++n] = b[i], a[n].w = cnt, cnt = 0;}slove(1, n);for (int i = 1; i <= n; i++)p[a[i].ans + a[i].w - 1] += a[i].w;for (int i = 0; i < m; i++)printf("%d\n", p[i]);return 0;
}

三维偏序/cdq分治/相关推荐

  1. BZOJ 2244 [SDOI2011]拦截导弹 (三维偏序CDQ+线段树)

    题目大意: 洛谷传送门 不愧为SDOI的duliu题 第一问?二元组的最长不上升子序列长度?裸的三维偏序问题,直接上$CDQ$ 由于是不上升,需要查询某一范围的最大值,并不是前缀最大值,建议用线段树实 ...

  2. BZOJ3262/Luogu3810 陌上花开 (三维偏序,CDQ)

    一个下午的光阴之死,凶手是细节与手残. 致命的一枪:BIT存权值时: for(; x <= maxx; x += x&-x) t[x] += w;//for(; x <= n; x ...

  3. [偏序关系与CDQ分治]【学习笔记】

    组合数学真是太棒了 $CDQ$真是太棒了(雾 参考资料: 1.<组合数学> 2.论文 课件 很容易查到 3.sro __stdcall 偏序关系 关系: 集合$X$上的关系是$X$与$X$ ...

  4. CDQ分治 + 树状数组 ---- C. Goodbye Souvenir(三维偏序+思维)

    题目链接 题目大意: 给定长度为nnn的数组, 定义数字XXX在[l,r][l,r][l,r]内的值为数字XXX在[l,r][l,r][l,r]内最后一次出现位置的下标减去第一次出现位置的下标 给定m ...

  5. HDU - 5517 Triple(三维偏序-二维树状数组/CDQ分治)

    题目链接:点击查看 题目大意:给出 n 个二元对 ( a , b ) 和 m 个三元对 ( c , d , e ),对于所有 b == e 的二元对和三元对,可以通过某种运算形成一个新的三元对 ( a ...

  6. 洛谷 - P3810 【模板】三维偏序(陌上花开)(CDQ分治套树状数组)

    题目链接:点击查看 题目大意:给出 n 个点,每个点有三个属性 a , b , c ,对于每个点 i 来说,求出有多少个 j 满足 a[ j ] <= a[ i ] && b[ ...

  7. 【原创】从BZOJ2683 简单题中 整 CDQ分治解决三维偏序

    CDQ分治 题目描述 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子 ...

  8. 分治算法,逆序对,三维偏序与CDQ分治

    分治算法基本思想 当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出. 对于这类问题,我们往往先把它分解成几个子问题,找到求出 ...

  9. hdu5618 (三维偏序,cdq分治)

    给定空间中的n个点,问每个点有多少个点小于等于自己. 先来分析简单的二维的情况,那么只要将x坐标排序,那么这样的问题就可以划分为两个子问题,,这样的分治有一个特点,即前一个子问题的解决是独立的,而后一 ...

最新文章

  1. 二叉树的先序建树后序输出
  2. 三大电机控制方案之DSP篇(1):TMS320F28335
  3. python常用函数和操作_python一条语句分析几个常用函数和概念 -
  4. j计算机实验室安全操作规范,实验室安全操作规程
  5. LeetCode 旋转数组 系列
  6. 收藏 | 聊聊 GPU 的计算能力上限
  7. 电脑机房用成品——名词解释
  8. VS C++ 字符大写变换 字符小写变换 tolower toupper
  9. MySQL主从介绍及配置
  10. chrome插件开发入门-保姆级攻略
  11. 2021南京扬子中学高考成绩查询,2021年南京高考各高中成绩及本科升学率数据排名及分析...
  12. 任务栏图标消失怎么办?三种方法教你快速恢复
  13. 什么是DAO,DAO是什么?DAO全面解析
  14. Java JDK8新特性Lambda表达式
  15. 常用的机器学习算法(使用 Python 和 R 代码)
  16. 对比分析冯诺依曼结构和哈佛结构。
  17. 618啦,你的钱包又被盯上啦!
  18. [附源码]JAVA毕业设计景区门票系统(系统+LW)
  19. 安装依赖报错:An unexpected error occurred: “E:\\ReactProject\\umi-project\\package.json:
  20. 一款免费的屏幕录制软件

热门文章

  1. OpenCV图像处理——重映射 remap函数
  2. MySQL 闪回原理与实战
  3. 数学建模常用算法汇总及python,MATLAB实现(五) —— 拟合
  4. 专业方向系列-01-大数据与故障诊断概述
  5. 实现isPrime()函数,参数为整数,要有异常处理,如果整数是质数,输出“是”,如果不是质数,输出“不是”。
  6. Matlab学习记录-矩阵的生成
  7. 记录我看的密码学方案中的技术,Shamir秘密共享,Schnorr零知识证明,EIGamal密码体制
  8. Here you go 干的好
  9. Prince and Princess UVA - 10635
  10. corosync+pacemaker+web集群