Luogu 3810 & BZOJ 3263 陌上花开/三维偏序 | CDQ分治

题面

\(n\)个元素,每个元素有三个值:\(a_i\), \(b_i\) 和 \(c_i\)。定义一个元素的偏序是三个值都小于等于它的值的元素的个数,对于\([0, n)\)的每个值\(i\),求偏序为\(i\)的元素个数。

题解

这道题我使用的是CDQ分治

这道题有三个维度,每个维度都要对应一个数据结构/算法,来逐个击破。

首先,按照\(a\)从小到大把所有元素排序,保证\(a\)从小到大。

然后,对于第二维进行分治:首先对mid两边的子区间分别处理,然后处理左边子区间内的元素对有边子区间内元素的贡献。

处理跨mid贡献,我们需要使用树状数组。把左右两个子区间分别按照\(b\)排序,对于右边的每个元素,先把左边所有b比它小、尚未加入树状数组的元素加入树状数组,即树状数组中左区间当前元素的\(c\)的对应位值上的值增加;然后计算右区间当前元素的\(c\)的对应位置的前缀和,把右区间当前元素的答案加上这个前缀和。

需要注意:

数据中有些元素是完全相同的,做的时候要去重,把原来的相同元素的个数当做新的唯一元素的权值。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
} const int N = 2000005;
int n, k, tot, tr[N], ans[N];
struct mem{
int a, b, c, cnt, sum;
bool operator < (const mem &B) const{
if(a != B.a) return a < B.a;
if(b != B.b) return b < B.b;
return c < B.c;
}
bool operator == (const mem &B) const{
return a == B.a && b == B.b && c == B.c;
}
} m[N], t[N];
bool cmp(const mem &A, const mem &B){
return A.b < B.b;
}
void add(int p, int x){
while(p <= k) tr[p] += x, p += p & -p;
}
int ask(int p){
int ret = 0;
while(p) ret += tr[p], p -= p & -p;
return ret;
}
void solve(int l, int r){
if(l == r) return;
int mid = (l + r) >> 1;
solve(l, mid), solve(mid + 1, r);
sort(m + l, m + mid + 1, cmp);
sort(m + mid + 1, m + r + 1, cmp);
int pl = l, pr = mid + 1;
while(pr <= r){
while(pl <= mid && m[pl].b <= m[pr].b)
add(m[pl].c, m[pl].cnt), pl++;
m[pr].sum += ask(m[pr].c);
pr++;
}
for(int i = l; i < pl; i++)
add(m[i].c, -m[i].cnt);
}
int main(){
read(n), read(k), tot = n;
for(int i = 1, a, b, c; i <= n; i++)
read(a), read(b), read(c), t[i] = (mem){a, b, c, 0, 0};
sort(t + 1, t + n + 1);
n = 0;
for(int i = 1; i <= tot; i++){
if(i == 1 || !(t[i] == t[i - 1]))
m[++n] = t[i];
m[n].cnt++;
}
solve(1, n);
for(int i = 1; i <= n; i++)
ans[m[i].sum + m[i].cnt - 1] += m[i].cnt;
for(int i = 0; i < tot; i++)
write(ans[i]), enter;
return 0;
}

Luogu 3810 & BZOJ 3262 陌上花开/三维偏序 | CDQ分治的更多相关文章

  1. BZOJ 3262 陌上花开 (三维偏序CDQ+树状数组)

    题目大意: 题面传送门 三维偏序裸题 首先,把三元组关于$a_{i}$排序 然后开始$CDQ$分治,回溯后按$b_{i}$排序 现在要处理左侧对右侧的影响了,显然现在左侧三元组的$a_{i}$都小于等 ...

  2. BZOJ3262 陌上花开 —— 三维偏序 CDQ分治

    题目链接:https://vjudge.net/problem/HYSBZ-3262 3262: 陌上花开 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit ...

  3. bzoj3262: 陌上花开 三维偏序cdq分治

    三维偏序裸题,cdq分治时,左侧的x一定比右侧x小,然后分别按y排序,对于左侧元素按y大小把z依次插入到树状数组里,其中维护每个左侧元素对右侧元素的贡献,在bit查询即可 /************* ...

  4. [bzoj] 3263 陌上花开 洛谷 P3810 三维偏序|| CDQ分治 && CDQ分治讲解

    原题 定义一个点比另一个点大为当且仅当这个点的三个值分别大于等于另一个点的三个值.每比一个点大就为加一等级,求每个等级的点的数量. 显然的三维偏序问题,CDQ的板子题. CDQ分治: CDQ分治是一种 ...

  5. BZOJ 2141 排队 (三维偏序CDQ+树状数组)

    题目大意:略 洛谷传送门 和 [CQOI2015]动态逆序对 这道题一样的思路 一开始的序列视为$n$次插入操作 把每次交换操作看成四次操作,删除$x$,删除$y$,加入$x$,加入$y$ 把每次操作 ...

  6. BZOJ 3295:[Cqoi2011]动态逆序对(三维偏序 CDQ分治+树状数组)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3295 题意:简单明了. 思路:终于好像有点明白CDQ分治处理三维偏序了.把删除操作看作是插入操作,那 ...

  7. 三维偏序[cdq分治学习笔记]

    三维偏序 就是让第一维有序 然后归并+树状数组求两维 cdq+cdq不会 告辞 #include <bits/stdc++.h> // #define int long long #def ...

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

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

  9. 洛谷P3810-陌上开花(三维偏序, CDQ, 树状数组)

    链接: https://www.luogu.org/problem/P3810#submit 题意: 一个元素三个属性, x, y, z, 给定求f(b) = {ax <= bx, ay < ...

随机推荐

  1. OpenCV中图像以Mat类型保存时各通道数据在内存中的组织形式及python代码访问各通道数据的简要方式

    以最简单的4 x 5三通道图像为例,其在内存中Mat类型的数据组织形式如下: 每一行的每一列像素的三个通道数据组成一个一维数组,一行像素组成一个二维数组,整幅图像组成一个三维数组,即: Mat.dat ...

  2. NO17--vue父子组件间单向数据流的解决办法

    在上一篇中讲解了父子组件之间是如何传值的,如果子组件需要改变传过来的数据供自己使用,或者想在子组件中改变传过来的数据并同步到父组件,那么直接改肯定是不行的,如果你这么做了,Vue 会在控制台给出警告. ...

  3. JAVA之运算符优先级

    Java运算符优先级从高到低 运算符 结合性 [ ] . ( ) (方法调用) 从左向右 ! ~ ++ -- +(一元运算) -(一元运算) 从右向左 * / % 从左向右 + - 从左向右 < ...

  4. plsql 不修改tnsnames.ora文件

    PLSQL 不修改tnsname直接连数据库的方式在PLSQL的Database中直接输入192.168.1.6:1521/VP.其中192.168.1.6为数据库的IP:1521为数据库端口:VP为 ...

  5. Final发布中间产物

    目录 ❶版本控制 ❷软件功能说明书 ❸WBS ❹PSP 一.版本控制 ①Git地址:https://git.coding.net/tianjiping/Android-tianjiping.git ② ...

  6. PC端上必应词典与金山词霸的测评分析

    1.  介绍 随着英语学习越来越普及,基本上现在每位大学生的电脑上都会有一款便捷的英语查词软件,这次我们团队选择测评的 是微软必应词典(3.5.0.4311)和金山词霸(2014.05.16.044) ...

  7. 面向对象程序设计第三次作业-Calculator

    题目: 最终代码: Scan.h: Print.h: Calaulator.cpp: 解题过程 看到题目后,在查询之后明白了这是多文件的题目,然后通过翁凯老师的视频讲解知道了.h和.cpp文件的区别和 ...

  8. Eclipse+MySQL+Tomcat web开发安装配置

    转载文章: 链接:https://blog.csdn.net/bbyyz01/article/details/78142126 1.Eclipse 这里选择Eclipse集成开发环境. 可以直接在官网 ...

  9. elasticsearch文档-字段的mapping

    mapping == Mapping是指定义如何将document映射到搜索引擎的过程,比如一个字段是否可以查询以及如何分词等,一个索引可以存储含有不同"mapping types" ...

  10. 蜗牛慢慢爬 LeetCode 10. Regular Expression Matching [Difficulty: Hard]

    题目 Implement regular expression matching with support for '.' and '*'. '.' Matches any single charac ...