zoukankan      html  css  js  c++  java
  • [BZOJ3262]:陌上花开(CDQ分治)

    题目传送门


    题目描述

    有$n$朵花,每朵花有三个属性:花形$(s)$、颜色$(c)$、气味$(m)$,用三个整数表示。
    现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
    定义一朵花$A$比另一朵花$B$要美丽,当且仅$S_ageqslant S_b,C_ageqslant C_b,M_ageqslant M_b$。
    显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。


    输入格式

    第一行为$N,K$,分别表示花的数量和最大属性值。
    以下$N$行,每行三个整数$s_i,c_i,m_i$,表示第$i$朵花的属性。


    输出格式

    包含$N$行,分别表示评级为$0...N-1$的每级花的数量。


    样例

    样例输入

    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


    数据范围与提示

    $1leqslant Nleqslant 100,000$。

    $1leqslant Kleqslant 200,000$。

    $1leqslant s_i,c_i,m_ileqslant K$。


    题解

    这道题好像可以用$bitset$,$CDQ$分治,$K-Dtree$解决。

    $bitset$好像跑不过,我也不清楚……

    最尴尬的是$K-Dtree$我不会……

    那么我就来讲讲$CDQ$分治。

    假设我们不考虑$m_i$,那么我们就变成了二元组排序,可以先将$s_i$排序,然后问题就转化成了:在一个数列里,找在$i$之前有几个数小于$c_i$。

    很显然要使用树状数组维护即可在$Theta (nlog n)$时间内求出答案。

    那么现在又加了一维,怎么办呢?

    首先,将这个三元组排序并去重,那么权值$a$已经随下标有序。

    然后我们就需要引入$CDQ$分治,假设当前处理的区间为$[L,R]$其中点为$M$,那么我们在处理当前区间的时候已经保证了$[L,M]$和$[M+1,R]$的有序,因为$[L,M]$中的$s_i$一定小于等于$[M+1,R]$中的$s_i$,所以我们只需要维护一个单调指针,按照$[L,M]$中的$c_i$的大小从小到大将其放入树状数组,并在其中查询前缀和即可。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec
    {
    	int s;
    	int c;
    	int m;
    	int x;
    	int id;
    }e[2000001];
    int n,k;
    int tr[8000001];
    int ans[2000001],q[2000001],b[2000001];
    bool cmp1(rec a,rec b){return a.s<b.s||(a.s==b.s&&a.c<b.c)||(a.s==b.s&&a.c==b.c&&a.m<b.m);}
    bool cmp2(rec a,rec b){return a.c<b.c||(a.c==b.c&&a.m<b.m)||(a.c==b.c&&a.m==b.m&&a.x<b.x);}
    int lowbit(int x){return x&-x;}
    void add(int x,int y)
    {
    	while(x<=k)
    	{
    		tr[x]+=y;
    		x+=lowbit(x);
    	}
    }
    int query(int x)
    {
    	int res=0;
    	while(x)
    	{
    		res+=tr[x];
    		x-=lowbit(x);
    	}
    	return res;
    }
    void cdq(int l,int r)//cdq分治
    {
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	cdq(l,mid);
    	cdq(mid+1,r);
    	sort(e+l,e+r+1,cmp2);
    	for(int i=l;i<=r;i++)
    	if(e[i].x<=mid)add(e[i].m,1);
    	else q[e[i].id]+=query(e[i].m);
    	for(int i=l;i<=r;i++)
    	if(e[i].x<=mid)add(e[i].m,-1);
    }
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d%d%d",&e[i].s,&e[i].c,&e[i].m);
    		e[i].id=i;
    	}
    	sort(e+1,e+n+1,cmp1);
    	for(int i=1;i<=n;)//手动去重
    	{
    		int flag=i+1;
    		while(flag<=n&&e[i].s==e[flag].s&&e[i].c==e[flag].c&&e[i].m==e[flag].m)flag++;
    		flag--;
    		while(i<=flag)
    		{
    			b[e[i].id]=e[flag].id;
    			i++;
    		}
    	}
    	for(int i=1;i<=n;i++)e[i].x=i;
    	cdq(1,n);
    	for(int i=1;i<=n;i++)
    		ans[q[b[e[i].id]]]++;
    	for(int i=0;i<n;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    使用 ServiceStack 构建跨平台 Web 服务
    .NET的微型Web框架 Nancy
    orcale复制表结构及其数据
    利用PL/SQL Developer工具导出数据到excel,导入excel数据到表
    PLSQL导入/导出数据方法
    基于Quqrtz.NET 做的任务调度管理工具
    Web监听器导图详解(转)
    GIT分支管理是一门艺术(转)
    我需要完全理解这部分代码才能确保它能够正常工作,如果由我来修复代码中的问题,我是不会这么写的,因此希望你也不要这么来写(转)
    不要学习代码,要学会思考(转)
  • 原文地址:https://www.cnblogs.com/wzc521/p/11253059.html
Copyright © 2011-2022 走看看