zoukankan      html  css  js  c++  java
  • cdq分治略解

    前言

    陌上花开,可缓缓归矣
                            ——吴越王

    1. 寓意:意思是:田间阡陌上的花开了,你可以一边赏花,一边慢慢回来。
    2. 隐意:春天都到了,你怎么还没有回来。形容吴越王期盼夫人早日归来的急切心情。

    Ask:那么这和cdq有什么关系呢?
    Answer:并没有什么关系,增强语文水平而已,现在来看一到题目:陌上花开。这就有关系了吧。

    题目大意是:有(n)个元素,第(i)个元素有(a_i,b_i,c_i)三个属性,设(f(i))表示满足(a_j≤a_i)(b_j≤b_i)(c_j≤c_i)(j)的数量。求(f(i)=d)的数量(din[0,n))

    做法1:暴力
    (O(n^2))的扫一遍求一下就好了。

    #include<bits/stdc++.h>
    int k,n,f[200001],a[200001],b[200001],c[200001],ans;
    int main(){
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;i++)
    		scanf("%d%d%d",&a[i],&b[i],&c[i]);
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++)
    			if(a[j]<=a[i]&&b[j]<=b[i]&&c[j]<=c[i]&&i!=j)
    				ans++;
    		f[ans]++,ans=0;
    	}
    	for(int i=0;i<n;i++)
    		printf("%d
    ",f[i]);
    }
    

    这个应该不需要多讲吧,普及组的难度,但不要说不需要,你在对拍的时候就需要他了

    做法2: K-DTree

    不会,我tcl

    做法三:cdq分治

    现在来正式讲一讲cdq分治

    cdq分治

    前置要求:

    1. 树状数组
    2. 基础分治
    3. 树状数组求逆序对

    逆序对的问题是二维的,我们只需要讲一维排序,然后在用树状数组维护即可。
    那么对于三维的陌上花开呢?我们还是可以用这个方法,首先先将数列按第一位排序,这样我们只需要考虑两维的情况。于是我们可以分治做了,将某一个序列([l,r]),分成段([l,mid])([mid+1,r]),然后在对([l,r])这段区间的第二维进行排序。若点在排序前属于([l,mid]),树状数组单点修改;否则该点在排序前属于([m+1,r]),便统计一次。(其实就是类似于树状数组求逆序对的操作)

    一定要记得去重,否则会出事的

    code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200001;
    struct node{
    	int x,y,z,id;
    }a[N];
    int c[N<<2],k,n,b[N],bj[N],f[N];
    int lowbit(int x){
    	return x&(-x);
    }
    int read(){
        int x=0,f=1;
    	char c=getchar();
        while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
        return f*x;
    }
    void add(int x,int v){
    	while(x<=k)
    		c[x]+=v,x+=lowbit(x);
    }
    int sum(int x){
    	int ans=0;
    	while(x)
    		ans+=c[x],x-=lowbit(x);
    	return ans;
    }
    bool cmp1(const node & a , const node & b ){
    	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;
    }
    bool cmp2(const node & a , const node & b ){
    	if(a.y!=b.y)
    		return a.y<b.y;
    	if(a.z!=b.z)
    		return a.z<b.z;
    	return a.x<b.x;
    }
    void cdq(int l,int r){
    	if(l==r)
    		return ;
    	int mid=(l+r)>>1,flag;
    	cdq(l,mid),cdq(mid+1,r);
    	sort(a+l,a+r+1,cmp2);
    	for(int i=l;i<=r;i++)
    		(a[i].x<=mid)?add(a[i].z,1),flag=i:b[a[i].id]+=sum(a[i].z);
    	for(int i=l;i<=r;i++)
    		if(a[i].x<=mid)
    			add(a[i].z,-1);
    }
    int main(){
    	n=read(),k=read();
    	for(int i=1;i<=n;i++)
    		a[i].x=read(),a[i].y=read(),a[i].z=read(),a[i].id=i;
    	sort(a+1,a+1+n,cmp1);
    	for(int i=1;i<=n;){
    		int j=i+1;
    		while(j<=n&&a[j].x==a[i].x&&a[j].y==a[i].y&&a[j].z==a[i].z)
    			j++;
    		while(i<j)
    			bj[a[i].id]=a[j-1].id,i++;
    	}
    	for(int i=1;i<=n;i++)
    		a[i].x=i;
    	cdq(1,n);
    	for(int i=1;i<=n;i++)
    		f[b[bj[a[i].id]]]++;
    	for(int i=0;i<n;i++)
    		printf("%d
    ",f[i]);
    }
    
    
  • 相关阅读:
    缓动函数速查表
    PHP递归题目
    linux下crontab定时执行本地脚本和定时访问指定url
    jsonp跨域js
    采用PHP函数uniqid生成一个唯一的ID
    php会话(session)生命周期概念介绍及设置更改和回收
    thinkphp3.2 学习
    PDO 查询mysql返回字段整型变为String型解决方法
    apache性能优化
    汉诺塔(四)(暴力)
  • 原文地址:https://www.cnblogs.com/hbxblog/p/10138165.html
Copyright © 2011-2022 走看看