P3810 【模板】三维偏序(陌上花开)(CDQ分治)
题目背景
这是一道模板题
可以使用bitset,CDQ分治,K-DTree等方式解决。
题目描述
有 nn 个元素,第 ii 个元素有 a_iai、b_ibi、c_ici 三个属性,设 f(i)f(i) 表示满足 a_j \leq a_iaj≤ai 且 b_j \leq b_ibj≤bi 且 c_j \leq c_icj≤ci 的 jj 的数量。
对于 d \in [0, n)d∈[0,n),求 f(i) = df(i)=d 的数量
输入格式
第一行两个整数 nn、kk,分别表示元素数量和最大属性值。
之后 nn 行,每行三个整数 a_iai、b_ibi、c_ici,分别表示三个属性值。
输出格式
输出 nn 行,第 d + 1d+1 行表示 f(i) = df(i)=d 的 ii 的数量。
输入输出样例
输入 #1
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
输出 #1
3 1 3 0 1 0 1 0 0 1
说明/提示
1 \leq n \leq 100000, 1 \leq k \leq 2000001≤n≤100000,1≤k≤200000
题解:初学习CDQ分治, 拿来这道三维偏序模板题练练手, 定义f(i)代表 a[j].x <= a[i].x && a[j].y <= a[i].y && a[j].z <= a[i].z 的j的个数.
对应 k = [0,n-1] 输出有多少个i 满足f(i) = k,分别输出.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 200010; ll c[maxn],n,k,cnt[maxn]; int lowbit(int x){return x & (-x);} void add(int pos,int x){ for(int i = pos;i <= k;i += lowbit(i)){ c[i] += x; } } ll query(int pos){ ll sum = 0; for(int i = pos; i >= 1;i -= lowbit(i)){ sum += c[i]; } return sum; } struct node{ int x,y,z,cnt,ans; bool operator != (const node w)const{ // 重载!=符号,用来判断两个结构体信息是否相同,只判断前三个信息就够了 if(x != w.x || y != w.y || z != w.z)return 1;//为1代表不等 else return 0; } }b[maxn],a[maxn]; int cmpx(node a,node b){//按x排序 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; } int cmpy(node a,node b){//按y排序 if(a.y != b.y)return a.y < b.y; return a.z < b.z; } void cdq(int l,int r){ if(l == r)return ; int mid = (l + r) / 2; cdq(l,mid),cdq(mid+1,r); sort(a + l,a + 1 + mid,cmpy); sort(a + mid + 1,a + r + 1,cmpy); int i = mid + 1,j = l; for(;i <= r;i++){ while(a[j].y <= a[i].y && j <= mid){ add(a[j].z,a[j].cnt),j++; } a[i].ans += query(a[i].z); } for(int i = l;i < j;i++)add(a[i].z,-a[i].cnt);//这一段区间处理完后对树状数组清零 } int main() { cin >> n >> k; for(int i = 1;i <= n;i++){ cin >> b[i].x >> b[i].y >> b[i].z; } sort(b+1,b+1+n,cmpx); int w = 0,top = 0; for(int i = 1;i <= n;i++){ w++; if(b[i] != b[i+1]){ a[++top] = b[i]; a[top].cnt = w; w = 0; } } cdq(1,top); for(int i = 1;i <= n;i++){//f(i)的值为a[i].ans + a[i].cnt - 1, 因为计算是去重了的 cnt[a[i].ans + a[i].cnt - 1] += a[i].cnt;//每个a[i] 都满足条件,加上a[i]出现的次数 } for(int i= 0;i < n;i++)cout << cnt[i] << endl; return 0; }