zoukankan      html  css  js  c++  java
  • P3810 【模板】三维偏序(陌上花开)

    (color{#0066ff}{题目描述})

    有 n 个元素,第 i 个元素有 (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) 的数量

    (color{#0066ff}{输入格式})

    第一行两个整数 n、 k,分别表示元素数量和最大属性值。

    之后 n 行,每行三个整数 (a_i 、b_i 、c_i) ,分别表示三个属性值。

    (color{#0066ff}{输出格式})

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

    (color{#0066ff}{输入样例})

    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
    

    (color{#0066ff}{输出样例})

    3
    1
    3
    0
    1
    0
    1
    0
    0
    1
    

    (color{#0066ff}{数据范围与提示})

    (1leq n leq 100000,1leq kleq 200000)

    (color{#0066ff}{题解})

    cdq 分治

    对序列分治,每次统计左区间每个元素对于右区间每个元素的贡献

    首先分别以x,y,z为1,2,3关键字排序

    那么现在x是有序的

    然后对序列cdq分治,每次把左右区间按y,z排序

    这样保证了左区间所有x(leq)右区间所有x,且左右区间y有序

    维护左区间的指针,for右区间每一个元素,只要左区间指针的元素y比当前小,就在权值树状数组上以z为下标++

    然后用当前的z收集ans

    注意千万不要单开ans数组收集答案

    因为当前元素在每次sort后会变成其他的,这样收集就乱了

    最后开桶统计即可

    #include<cstdio>
    #include<queue>
    #include<vector>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #define _ 0
    #define LL long long
    #define Space putchar(' ')
    #define Enter putchar('
    ')
    #define fuu(x,y,z) for(int x=(y),x##end=z;x<=x##end;x++)
    #define fu(x,y,z)  for(int x=(y),x##end=z;x<x##end;x++)
    #define fdd(x,y,z) for(int x=(y),x##end=z;x>=x##end;x--)
    #define fd(x,y,z)  for(int x=(y),x##end=z;x>x##end;x--)
    #define mem(x,y)   memset(x,y,sizeof(x))
    #ifndef olinr
    inline char getc()
    {
    	static char buf[100001],*p1=buf,*p2=buf;
    	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)? EOF:*p1++;
    }
    #else
    #define getc() getchar()
    #endif
    template<typename T>inline void in(T &x)
    {
    	int f=1; char ch; x=0;
    	while(!isdigit(ch=getc()))(ch=='-')&&(f=-f);
    	while(isdigit(ch)) x=x*10+(ch^48),ch=getc();
    	x*=f;
    }
    int n,k;
    struct BIT
    {
    	private:
    		int c[205050];
    		#define low(x) ((x)&(-x))
    	public:
    		inline void add(int pos,int v) {for(int i=pos;i<=k;i+=low(i)) c[i]+=v;}
    		inline int query(int pos) {int ans=0; for(int i=pos;i;i-=low(i)) ans+=c[i]; return ans;} 
    };
    struct node
    {
    	int x,y,z;
    	int num,ans;
    	friend bool operator != (const node &a,const node &b)
    	{
    		return a.x!=b.x||a.y!=b.y||a.z!=b.z;
    	}
    }e[300000];
    BIT t;
    int ans[300000];
    inline void cdq(int l,int r)
    {
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	cdq(l,mid);cdq(mid+1,r);
    	std::sort(e+l,e+mid+1,[](const node &a,const node &b){return (a.y<b.y)||(a.y==b.y&&a.z<b.z);});
    	std::sort(e+mid+1,e+r+1,[](const node &a,const node &b){return (a.y<b.y)||(a.y==b.y&&a.z<b.z);});
    	int now=l;
    	fuu(i,mid+1,r)
    	{
    		//每一个都会产生贡献,所以是num
    		while(now<=mid&&e[now].y<=e[i].y) t.add(e[now].z,e[now].num),now++;
    		e[i].ans+=t.query(e[i].z);
    	}
    	fuu(i,l,now-1) t.add(e[i].z,-e[i].num);
    }
    int main()
    {
    	in(n),in(k);
    	fuu(i,1,n) in(e[i].x),in(e[i].y),in(e[i].z),e[i].num=1;
    	std::sort(e+1,e+n+1,[](const node &a,const node &b){return (a.x<b.x)||(a.x==b.x&&(a.y<b.y))||(a.x==b.x&&a.y==b.y&&a.z<b.z);});
    	int tmp=0;
    	//去重,相同的压一起(跟自己相同的算在ans的一部分,但自己对自己无贡献)
    	fuu(i,1,n)
    	{  
    		if(e[i]!=e[i-1]) e[++tmp]=e[i];
    		else e[tmp].num++;
    	} 
    	cdq(1,tmp);
    	//ans里面套的是当前元素的答案(要加上相同的-自己)
    	//外面因为跟自己相同的都是成立的,所以+=个数
    	fuu(i,1,tmp) ans[e[i].ans+e[i].num-1]+=e[i].num;
    	fuu(i,0,n-1) printf("%d
    ",ans[i]);
    	return ~~(0^_^0);
    }
    
  • 相关阅读:
    MVP模式
    开源代码SlidingMenu的使用
    常用命令(Linux、Android、adb)
    一文搞清楚Minor GC、Major GC 、Full GC 之间的关系
    阿里最新38道Java面试题解析(MyBatis+消息队列+Redis)
    从5个方面让你真正了解Java内存模型
    深入理解JVM:元空间大小详细解析
    面试必问:JVM类加载机制详细解析
    5个点彻底搞清楚SpringBoot注解
    8种创建Java线程的方式,你知道几个?
  • 原文地址:https://www.cnblogs.com/olinr/p/10079577.html
Copyright © 2011-2022 走看看