• cdq分治模板


    可求解多维偏序问题
    三维偏序(陌上花开)
    有 nn 个元素,第 ii 个元素有 (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 的数量

    输入格式
    第一行两个整数 nn、kk,分别表示元素数量和最大属性值。
    之后 nn 行,每行三个整数 (a_i)(b_i)(c_i) ,分别表示三个属性值。

    输出格式
    输出 n 行,第 d + 1 行表示 f(i) = d的 i 的数量。
    输入输出样例

    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
    

    不同于普通分治的是:左右两个子区间并不是独立的,虽然不能使得两个子区间相互独立,但是通过某一维的排序,使得左子区间答案相对于右子区间独立,而右子区间最终计算时加上左子区间的贡献即可
    因为可以等于,如果不去重的话子区间答案可能不独立。
    如:a,b,c,d分为ab,cd,如果b和c相等,分治就不对了

    #include<bits/stdc++.h>
    using namespace std;
    char buf[1<<20],*P1=buf,*P2=buf;
    #define gc() (P1==P2&&(P2=(P1=buf)+fread(buf,1,1<<20,stdin),P1==P2)?EOF:*P1++)
    #define TT template<class T>inline
    TT bool read(T &x){
        x=0;char c=gc();bool f=0;
        while(c<48||c>57){if(c==EOF)return 0;f^=(c=='-'),c=gc();}
        while(47<c&&c<58)x=x*10+c-48,c=gc();
        if(f)x=-x;return 1;
    }
    TT bool read(T&a,T&b){return read(a)&&read(b);}
    TT bool read(T&a,T&b,T&c){return read(a)&&read(b)&&read(c);}
    typedef long long ll;
    #define lowbit(x) (x&(-x))
    const ll MAXN=1e5+8,mod=1e9+7,inf=0x3f3f3f3f;
    struct Node{int a,b,c,num,ans;}node[MAXN],tmp[MAXN];
    //num:去重后的和数量,该点的答案
    bool cmp(const Node&x,const Node&y){
        if(x.a^y.a)return x.a<y.a;
        if(x.b^y.b)return x.b<y.b;
        return x.c<y.c;
    }
    bool equal(const Node&x,const Node&y){return x.a==y.a&&x.b==y.b&&x.c==y.c;}
    int n,k,s[MAXN<<1];
    inline void add(int p,int v){
        while(p<=k){
            s[p]+=v;
            p+=lowbit(p);
        }
    }
    inline int query(int p){
        int res=0;
        while(p){
            res+=s[p];
            p-=lowbit(p);
        }return res;
    }
    int d[MAXN];
    void cdq(int l,int r){
        if(l==r)return;//如果只有一个点,ans=0;
        int m=(l+r)>>1;
        cdq(l,m);cdq(m+1,r);//递归求解子区间
        for(int i=l,j=m+1,p=l;i<=m||j<=r;++p){//更新答案的同时就可以归并排序
            if(i<=m&&(j>r||node[i].b<=node[j].b))
                add(node[i].c,node[i].num),tmp[p]=node[i++];
            else node[j].ans+=query(node[j].c),tmp[p]=node[j++];
        }
        for(int i=l;i<=m;++i)add(node[i].c,-node[i].num);//将树状数组清空
        for(int i=l;i<=r;++i)node[i]=tmp[i];
    }
    int main() {
        read(n,k);
        for(int i=1;i<=n;++i){
            read(node[i].a,node[i].b,node[i].c);
            node[i].num=1;
            node[i].ans=0;
        }
        sort(node,node+1+n,cmp);
        int cnt=1;//去重
        for(int i=2;i<=n;++i){
            if(equal(node[i],node[cnt]))node[cnt].num++;
            else node[++cnt]=node[i];
        }
        cdq(1,cnt);
        //这里的ans是只计算了不想等的答案,得加上重复的数量。
        for(int i=1;i<=cnt;++i)d[node[i].ans+node[i].num-1]+=node[i].num;
        for(int i=0;i<n;++i)printf("%d
    ",d[i]);
        return 0;
    }
    
  • 相关阅读:
    javascript keycode大全
    在WEB环境下打印报表的crystal的解决方案
    Trim()
    C#应用结构体变量
    锚点定位
    C# 按地址传值
    [GIIS]JS 图片 Preview
    c# 模拟网站登陆
    此数据库没有有效所有者,因此无法安装数据库关系图支持对象" 解决方法
    风讯.NET与NETCMS的选择—开源.NET内容管理系统
  • 原文地址:https://www.cnblogs.com/foursmonth/p/14161860.html
Copyright © 2020-2023  润新知