• CDQ分治


    CDQ分治

    CDQ分治是一种分治类算法,可以解决三维以及多维偏序 ( CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ套CDQ ) 问题。

    其思想类似于归并排序,在子问题对当前问题有贡献时可以使用QAQ 例如板题陌上花开(三位偏序) (我不会CDQ套CDQ)首先我们按照(a)升序排序 显然接下来我们需要解决的问题就是(b,c) 的偏序问题了 因为我们已经按照a升序排序了 所以在分治后的左区间在满足(b_l<b_r)&&(c_l<c_r)的 时候会对右区间产生贡献 我们可以分别对左区间,右区间按照(b)排序,然后用树状数组维护(c)就可以了

    注意要去重,因为如果相同的数却被分在了左右区间 会产生意想不到的结果哦QAQ

    另外如果将区间按照(b)排序了 那么如果(b_r<b_l) 就可以直接更新(b_r)对应的(data)(ans)了。因为显然(b_{l+1}>b_r) (毕竟按照b排序了)

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    using namespace std;
    const int maxn=100100;
    int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    struct node{
    	int a,b,c,cnt,ans;
    	#define a(x) num[x].a
    	#define b(x) num[x].b
    	#define c(x) num[x].c 
    }num[maxn],data[maxn];
    inline bool cmpl(node x,node y){return x.a<y.a || (x.a==y.a && (x.b<y.b || (x.b==y.b && x.c<y.c)));}
    inline bool cmpll(node x,node y){return x.b<y.b || (x.b==y.b && x.c<y.c);}
    int nn,n,k,tot,tree[maxn<<1],shawn[maxn<<1];
    void add(int x,int y){
    	for(;x<=k;x+=(x&-x)){
    		tree[x]+=y;
    	}
    }
    int query(int x){
    	int sum=0;
    	for(;x;x-=(x&-x)){
    		sum+=tree[x];
    	}
    	return sum;
    }
    void cdq(int l,int r){
    	if(l==r) return ;
    	int mid=l+r>>1;
    	cdq(l,mid);cdq(mid+1,r);
    	sort(data+l,data+mid+1,cmpll);sort(data+mid+1,data+r+1,cmpll);
    	int i=mid+1,j=l;
    	for(;i<=r;i++){
    		while(data[j].b<=data[i].b && j<=mid){
    			add(data[j].c,data[j].cnt);j++;
    		}
    		data[i].ans+=query(data[i].c);
    	}
    	for(i=l;i<j;i++)
    		add(data[i].c,-data[i].cnt);
    }
    int main(){
    	nn=read();k=read();
    	for(int i=1;i<=nn;i++){
    		a(i)=read();b(i)=read();c(i)=read();
    	}
    	sort(num+1,num+1+nn,cmpl);
    	for(int i=1;i<=nn;i++){
    		tot++;
    		if(a(i)!=a(i+1) || b(i)!=b(i+1) || c(i)!=c(i+1)){data[++n]=num[i];data[n].cnt=tot;tot=0;}
    	}
    	cdq(1,n);
    	for(int i=1;i<=n;i++){
    		shawn[data[i].ans+data[i].cnt-1]+=data[i].cnt;
    	}
    	for(int i=0;i<nn;i++)
    		printf("%d
    ",shawn[i]);
    	return 0;
    }
    
  • 相关阅读:
    1.Math函数对象
    1.日期与时间
    使用object literal替换switch
    Array数组去重
    flexbox弹性布局
    web移动端一些常用知识
    解决网页ICON图标无法显示的问题
    观察者模式和发布订阅模式的区别
    JS延迟加载的几种方式
    前端 api 请求缓存方案
  • 原文地址:https://www.cnblogs.com/mendessy/p/11822841.html
Copyright © 2020-2023  润新知