P3810 【模板】三维偏序(陌上花开)cdq分治

传送门:https://www.luogu.org/problemnew/show/P3810

cdq分治的模板题,第一层外部排序,第二层cdq归并排序,这个时候不用考虑第一次的顺序,第三次用树状数组。

注意,不要用memset,用队列保存加上的值,最后在把加上的值减去就行了。

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>
//#include <unordered_map>
/*

⊂_ヽ
  \\ Λ_Λ  来了老弟
   \(‘?‘)
    > ⌒ヽ
   /   へ\
   /  / \\
   ? ノ   ヽ_つ
  / /
  / /|
 ( (ヽ
 | |、\
 | 丿 \ ⌒)
 | |  ) /
‘ノ )  L?

*/

using namespace std;
#define lson (l , mid , rt << 1)
#define rson (mid + 1 , r , rt << 1 | 1)
#define debug(x) cerr << #x << " = " << x << "\n";
#define pb push_back
#define pq priority_queue

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
//typedef __int128 bll;
typedef pair<ll ,ll > pll;
typedef pair<int ,int > pii;
typedef pair<int,pii> p3;

//priority_queue<int> q;//这是一个大根堆q
//priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
#define fi first
#define se second
//#define endl ‘\n‘

#define boost ios::sync_with_stdio(false);cin.tie(0)
#define rep(a, b, c) for(int a = (b); a <= (c); ++ a)
#define max3(a,b,c) max(max(a,b), c);
#define min3(a,b,c) min(min(a,b), c);

const ll oo = 1ll<<17;
const ll mos = 0x7FFFFFFF;  //2147483647
const ll nmos = 0x80000000;  //-2147483648
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f; //18
const int mod = 998244353;
const double esp = 1e-8;
const double PI=acos(-1.0);
const double PHI=0.61803399;    //黄金分割点
const double tPHI=0.38196601;

template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<‘0‘||ch>‘9‘) f|=(ch==‘-‘),ch=getchar();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x=f?-x:x;
}

inline void cmax(int &x,int y){if(x<y)x=y;}
inline void cmax(ll &x,ll y){if(x<y)x=y;}
inline void cmin(int &x,int y){if(x>y)x=y;}
inline void cmin(ll &x,ll y){if(x>y)x=y;}
#define MODmul(a, b) ((a*b >= mod) ? ((a*b)%mod + 2*mod) : (a*b))
#define MODadd(a, b) ((a+b >= mod) ? ((a+b)%mod + 2*mod) : (a+b))

/*-----------------------showtime----------------------*/
            const int maxn = 1e5+9;
            struct node{
                int x,y,z;
                int id;
            }a[maxn],b[maxn],tmp[maxn];
            bool cmp(node a,node b){
                if(a.x != b.x) return a.x < b.x;
                if(a.y != b.y) return a.y < b.y;
                else return a.z < b.z;
            }
            int cnt[maxn],ans[maxn];

            int sum[maxn*2];
            int lowbit(int x){
                return x & (-x);
            }
            void add(int x,int c){
                while(x < maxn*2){
                    sum[x] += c;
                    x += lowbit(x);
                }
            }
            int getsum(int x){
                int res = 0;
                while(x > 0) {
                    res += sum[x];
                    x -= lowbit(x);
                }
                return res;
            }
            int lazy[maxn];
            queue<int>que;
            void cdq(int le,int ri){
                int mid = (le + ri) >> 1;
                if(ri - le <= 0) return ;
                cdq(le, mid);   cdq(mid+1, ri);

         //       memset(sum, 0, sizeof(sum));

                int p = le, q = mid+1;
                int id = 0;
                while(p <= mid && q <= ri){
                    if(a[p].y <= a[q].y) {
                        add(a[p].z, lazy[a[p].id]);
                        que.push(p);
                        tmp[++id] = a[p++];
                    }
                    else {
                        cnt[a[q].id] += getsum(a[q].z);
                        tmp[++id] = a[q++];
                    }
                }
                while(p <= mid) tmp[++id] = a[p++];
                while(q <= ri) {
                    cnt[a[q].id] += getsum(a[q].z);
                    tmp[++id] = a[q++];
                }
                while(!que.empty()){
                    int u = que.front(); que.pop();
                    add(a[u].z, -lazy[a[u].id]);
                }

                for(int i=1; i<=id; i++) a[i+le-1] = tmp[i];

            }
           // int out[maxn];
           map<p3,int>mp;

int main(){
            int n,k;
            scanf("%d%d", &n, &k);
            int tot = 0;
            rep(i, 1, n) {
                int x, y, z;
                scanf("%d%d%d", &x, &y, &z);
             //   read(x);read(y);read(z);
                p3 tp = p3(x, pii(y, z));
                if(mp.count(tp)) lazy[mp[tp]]++,cnt[mp[tp]]++;
                else {
                    tot++;
                    a[tot].id = tot;
                    a[tot].x = x;
                    a[tot].y = y;
                    a[tot].z = z;
                    mp[tp] = tot;
                    lazy[tot] = 1;
                }
            }
            sort(a+1, a+1+tot, cmp);

            cdq(1, tot);

            rep(i, 1, tot) ans[cnt[a[i].id]] += lazy[a[i].id];
            /*
            rep(i, 1, n) {
                out[a[i].id] = cnt[a[i].id];
            }
            rep(i, 1, n)
                cout<<cnt[i]<<" ";
            cout<<endl;
            */
            rep(i, 0, n-1) printf("%d\n", ans[i]);
            return 0;
}

原文地址:https://www.cnblogs.com/ckxkexing/p/10459390.html

时间: 2024-10-08 00:53:53

P3810 【模板】三维偏序(陌上花开)cdq分治的相关文章

三维偏序:CDQ分治

cdq分治是一种常用的降维手段,可以解决偏序问题. 题目 给定$n$个三元组$(x, y, z)$,给定一个$f(a)$,表示所有元素$b$(自己不算),它的$x,y,z$均小于等于$a$的对应$x,y,z$,求$[0, n)$中每种$f$值的个数. $n \leq 100000$ $x, y, z \leq 200000$ 简单模型 一维:仅有$x$:按$x$排序即可. 二维:有$(x, y)$,按先$x$后$y$顺序排序,然后将$y$值用树状数组统计. 三维偏序:cdq分治解法 思想:类似归

BZOJ3262/洛谷P3810 陌上花开 CDQ分治 三维偏序 树状数组

原文链接http://www.cnblogs.com/zhouzhendong/p/8672131.html 题目传送门 - BZOJ3262 题目传送门 - 落谷P3810 题意 有$n$个元素,第$i$个元素有$a_i$.$b_i$.$c_i$三个属性,设$f(i)$表示满足$a_j\leq a_i$且$b_j\leq b_i$且$c_j\leq c_i$的$j$的数量.对于$d\in [0,n)$,求$f(i)=d$的数量. $n\leq 100000,max\{a_i,b_i,c_i|i

BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]

Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值. 以下N行,每

HDU 5126(stars)四维偏序,cdq分治

题意:给两种操作,进行5万次.操作一:加入一个三维序偶(a,b,c)到集合S里:第二种操作,给两个三维序偶(a1,b1,c1)和(a2,b2,c2),问当前S里有多少个序偶(a,b,c)满足a1<=a<=a2, b1<=b<=b2, c1<=c<=c2.题目保证了a1<=a2,b1<=b2,c1<=c2.所有数在[1,1e9]内 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5126 解法:将操作编号也加入到

luogu3810 陌上花开 (cdq分治)

求三维偏序 设三维为a,b,c.先对a排序,这样i的偏序就只能<i. 然而排序的时候需要三个维度都判断一遍,最后还要去重,不然会出现实际应该记答案的数出现在它后面的情况. (排序用的函数里不要写类似于<=之类的东西啊..会出奇奇怪怪的问题的(RE)) 然后分治来做,我们在做区间[l,r]的时候,先去做[l,m]和[m+1,r] 之后左区间[l,m],右区间[m+1,r]都已经按照b排好序了,而且左右两区间内部的答案已经统计过了,所以现在只要考虑左区间中满足(右区间的数)的数量就好了. 那么就也

BZOJ3262陌上花开 CDQ分治_BIT+Treap

三个属性, 第一个属性用cdq分治处理, 以第一个属性为关键字从小到大排序, 那么考虑一朵花的等级, 只需考虑排在其前面的花的其他属性(特殊情况是有相同的花,根据题意,对一段相同的花,以排在最后的一朵花的答案为准), 第二三维可以用树状数组加Treap解决, 以每朵花第二属性数值作为位置(因为最大属性k < 2e5, 可以不用离散化, 直接用属性的数值对应树状数组中的下标), 树状数组的每个节点建一颗Treap, 这颗Treap里存的是相应区间里的花的第三个属性, 询问时类似于树状数组求前缀和,

HDU4742----Pinball Game 3D(三维LIS、CDQ分治)

题意:三维空间内 n个小球,对应坐标(x,y,z).输出LIS的长度以及方案数. 首先可以先按x排序,先降低一维,然后 剩下y .z,在y上进行CDQ分治,按y的大小用前面的更新后面的.z方向离散化之后用树状数组维护就可以了. 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <stack

BZOJ 3262: 陌上花开 cdq分治 树状数组

https://www.lydsy.com/JudgeOnline/problem.php?id=3262 cdq分治板子题,一维排序,一维分治(cdq里的队列),一维数据结构(树状数组). 学dp优化前来复习--以前好像写过这道题但是没写博客啊--在校oj上写的题都没怎么写博客,追悔莫及 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #

hdu 4742 Pinball Game 3D(三维LIS&amp;amp;cdq分治&amp;amp;BIT维护最值)

Pinball Game 3D Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 688    Accepted Submission(s): 276 Problem Description RD is a smart boy and excel in pinball game. However, playing common 2D p

bzoj 3262: 陌上花开 -- CDQ分治

3262: 陌上花开 Time Limit: 20 Sec  Memory Limit: 256 MB Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,00