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

思路

看到这种偏序类的题目,而且不要求强制在线,可以立刻想到cdq分治

注意这题有一个问题,就是询问的是小于等于而不是小于,如果相等的话两个元素会相互贡献,而cdq的特点是右区间不能对左边有影响,所以要先去重,再然后就是板子

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,maxn;
namespace BIT{
    int bit[200100];
    int lowbit(int x){
        return x&(-x);
    }
    void add(int pos,int val){
        while(pos<=maxn){
            bit[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    int query(int pos){
        int ans=0;
        while(pos){
            ans+=bit[pos];
            pos-=lowbit(pos);
        }
        return ans;
    }
    void clear(int pos){
        while(pos<=maxn){
            if(bit[pos])
                bit[pos]=0;
            else
                break;
            pos+=lowbit(pos);
        }
    }
}
struct Num{
    int a,b,c,val;
    bool operator == (const Num &bx) const{
        if(a==bx.a&&b==bx.b&&c==bx.c)
            return true;
        return false;
    }
    bool operator < (const Num &bx) const{
        if(a<bx.a)
            return true;
        else if(a==bx.a&&b<bx.b)
            return true;
        else if(a==bx.a&&b==bx.b&&c<bx.c)
            return true;
        else return false;
    }
}a[100100],num[100100];
int ans[100100],d[100100];
int cntnum=0,qid,aid;
struct Query{
    int posx,valy,val,aid;
}query[100100<<1];
Query tmp[100100<<1];
void cdq(int L,int R){
    // printf("%d %d\n",L,R);
    if(R<=L+1)
        return;
    int mid=(L+R)>>1;
    cdq(L,mid);
    cdq(mid,R);
    int l=L,r=mid,tot=0;
    while(l<mid&&r<R){
        if(query[l].posx<=query[r].posx){
            BIT::add(query[l].valy,query[l].val);
            tmp[++tot]=query[l++];
        }
        else{
            ans[query[r].aid]+=BIT::query(query[r].valy);
            tmp[++tot]=query[r++];
        }
    }
    while(l<mid)
        tmp[++tot]=query[l++];
    while(r<R){
        ans[query[r].aid]+=BIT::query(query[r].valy);
        tmp[++tot]=query[r++];
    }
    for(int i=1;i<=tot;i++){
        BIT::clear(tmp[i].valy);
        query[i+L-1]=tmp[i];
    }
}
int main(){
    scanf("%d %d",&n,&maxn);
    for(int i=1;i<=n;i++)
        scanf("%d %d %d",&a[i].a,&a[i].b,&a[i].c),a[i].val=1;
    sort(a+1,a+n+1);
    // printf("ok\n");
    // for(int i=1;i<=n;i++)
    //     printf("%d %d %d\n",a[i].a,a[i].b,a[i].c);
    num[++cntnum]=a[1];
    for(int i=1;i<=n-1;i++){
        if(a[i]==a[i+1])
            num[cntnum].val++;
        else
            num[++cntnum]=a[i+1];
    }
    for(int i=1;i<=cntnum;i++){
        query[++qid].posx=num[i].b;
        query[qid].aid=++aid;
        query[qid].valy=num[i].c;
        query[qid].val=num[i].val;
    }
    // printf("ok\n");
    cdq(1,qid+1);
    for(int i=1;i<=qid;i++){
        d[ans[query[i].aid]+query[i].val-1]+=query[i].val;
    }
    for(int i=0;i<=n-1;i++)
        printf("%d\n",d[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/dreagonm/p/10122514.html

时间: 2024-10-10 10:04:12

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