zoukankan      html  css  js  c++  java
  • bzoj3262 陌上花开

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


    HINT
    1<=N<=100,000,1<=K<=200,000

    Sample Input
    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

    Sample Output
    3
    1
    3
    0
    1
    0
    1
    0
    0
    1

    https://blog.csdn.net/reverie_mjp/article/details/52462651

    Sol:

    【这种算法一般只能解决非强制在线问题。既然它属于分治,它的思想也必然是分治的,即二分操作。一般情况下,通过用树维护操作的区间来查找答案】

    【我们把[l,r]当做当前需处理的区间,则我们递归处理[l,mid],每次对于[l,mid]里的操作数,枚举处理它对[mid+1,r]区间的操作的影响,再递归处理[mid+1,r]区间】

    【对于本题来说,每个操作包含三维,首先按第一维关键字排序,并去重,数组中记录相同的花有多少朵。然后CDQ分治处理,处理时,将[l,mid]区间和[mid+1,r]区间分别按第二维关键字排序,并用树状数组以第三维为下标,维护每一朵花的出现次数。每一次处理[l,mid]对[mid+1,r]的影响时,只需考虑第二维的影响即可(因为[l,mid]区间的x一定小于[mid+1,r]区间的x,而第三维用树状数组维护也不需要考虑),当第二维符合要求时,将它的影响加入树状数组中。每查找完[mid+1,r]区间的一个操作,就更新答案】

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    struct flower{
    	int x,y,z;
    	int cnt,ans;
    }d[1000010];
    int tree[3000010],n,k,tot,num[1000010];
    int tmp(flower a,flower b)
    {
    	if(a.x<b.x) return 1;
    	if(a.x>b.x) return 0;
    	if(a.y<b.y) return 1;
    	if(a.y>b.y) return 0;
    	if(a.z<b.z) return 1;
    	return 0;
    }
    int cmp(flower a,flower b)
    {
    	if(a.y<b.y) return 1;
    	if(a.y>b.y) return 0;
    	if(a.z<b.z) return 1;
    	if(a.z>b.z) return 0;
    	if(a.x<b.x) return 1;
    	return 0;
    }
    inline int lowbit(int x)
    {
    	return x&(-x);
    }
    inline void updata(int x,int v)
    {
    	while(x<=k)
    	 {
    	 	tree[x]+=v;
    	 	x+=lowbit(x);
    	 }
    	return;
    }
    inline int ask(int x)
    {
    	int sum=0;
    	while(x)
    	 {
    	 	sum+=tree[x];
    	 	x-=lowbit(x);
    	 }
    	return sum;
    }
    void CDQ(int l,int r)
    {
    	if(l==r) 
    	 {
    	 	d[l].ans+=d[l].cnt-1;
    	 	return;
    	 }
    	int mid=(l+r)>>1;
    	CDQ(l,mid); 
    	CDQ(mid+1,r);
    	sort(d+l,d+mid+1,cmp);
    	sort(d+mid+1,d+r+1,cmp);
    	//按y,z为第一,第二关键字进行排序 
    	int j=l;
    	//统计左区间对右区间的贡献值 
    	for(int i=mid+1;i<=r;++i)
    	 {
    	 	while(j<=mid&&d[j].y<=d[i].y)
    	 	//如果j的y值小于等于i的y值的话
    		 //由于前面已按x值排序好了,所以j的x值也是小于等于i的x值的 
    		   updata(d[j].z,d[j].cnt),++j;
    		 //注意更新的位置,在j的z值位置,加上j这种花的数目 
    	    d[i].ans+=ask(d[i].z);
    	    //从j开始的若干对花对于i这种花的贡献
    		//就只要看在[1,d[i].z]这个区间,我们加入了多少值 
    	 }
    	//清空下影响,目前算得是[l,mid]对[mid+1,r]的影响
    	//当我们对[mid+1,r]这个区间进行计算时,也将分成两半来进行计算
    	//前期算[l,mid]时,有些值就可以打到[mid+1,r]的右边那一半去
    	//但其实这是不对的,因为我们要算的是[mid+1,r]的左半边,对右半边的影响 
    	for(int i=l;i<j;++i) 
    	    updata(d[i].z,-d[i].cnt);
    	    
    }
    int main()
    {
    	
    	int i,j;
    	scanf("%d%d",&n,&k);
    	for(i=1;i<=n;++i) 
    	    scanf("%d%d%d",&d[i].x,&d[i].y,&d[i].z),d[i].ans=1;
    	sort(d+1,d+n+1,tmp);
    	//按x,y,z为第一,二,三关键字进行排序 
    	for(i=1;i<=n;++i)
    	//对同类的花进行合并 
    	 if(i!=1&&d[i].x==d[i-1].x&&d[i].y==d[i-1].y&&d[i].z==d[i-1].z) 
    	    d[tot].cnt++;
    	  else 
    	       d[++tot]=d[i],d[tot].cnt=1;
    	CDQ(1,tot);
    	sort(d+1,d+tot+1,tmp);
    	for(i=1;i<=tot;++i) 
    	     num[d[i].ans]+=d[i].cnt;
    	for(i=1;i<=n;++i) 
    	    printf("%d
    ",num[i]);
    	return 0;
    }
    

      

     

      

  • 相关阅读:
    CodeForces 785D Anton and School
    CodeForces 785C Anton and Fairy Tale
    CodeForces 785B Anton and Classes
    CodeForces 785A Anton and Polyhedrons
    爱奇艺全国高校算法大赛初赛C
    爱奇艺全国高校算法大赛初赛B
    爱奇艺全国高校算法大赛初赛A
    EOJ 3265 七巧板
    EOJ 3256 拼音魔法
    EOJ 3262 黑心啤酒厂
  • 原文地址:https://www.cnblogs.com/cutemush/p/14208511.html
Copyright © 2011-2022 走看看