[模板]三维偏序

一、题目

点此看题

二、解法

c d q cdq 的板题,首先对 a a 从小到大排序,然后考虑合并两段,因为已经保证了 a a 的顺序,我们先对 b b 排序,然后扫右边,把左边 b b 小于等于当前值的加入树状数组,然后查询 c c 比当前值小的个数和。

有一个细节就是 a , b , c a,b,c 三个值都相等的时候要合并成一个。

#include <cstdio>
#include <algorithm>
using namespace std;
const int M = 200005;
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,k,cnt[M],bit[M];
struct node
{
	int a,b,c,w,ans;
}p[M];
bool cmp1(node x,node y)
{
	if(x.a==y.a)
	{
		if(x.b==y.b) return x.c<y.c;
		return x.b<y.b;
	}
	return x.a<y.a;
}
bool cmp2(node x,node y)
{
	if(x.b==y.b) return x.c<y.c;
	return x.b<y.b;
}
int lowbit(int x)
{
	return x&(-x);
}
void ins(int x,int f)
{
	for(int i=x;i<=k;i+=lowbit(i))
		bit[i]+=f;
}
int ask(int x)
{
	int r=0;
	for(int i=x;i>=1;i-=lowbit(i))
		r+=bit[i];
	return r;
}
void cdq(int l,int r)
{
	if(l==r) return ;
	int mid=(l+r)>>1,i=l;
	cdq(l,mid);cdq(mid+1,r);
	sort(p+l,p+mid+1,cmp2);
	sort(p+mid+1,p+r+1,cmp2);
	for(int j=mid+1;j<=r;j++)
	{
		while(i<=mid && p[i].b<=p[j].b)
		{
			ins(p[i].c,p[i].w);i++;
		}
		p[j].ans+=ask(p[j].c);
	}
	for(i--;i>=l;i--)
		ins(p[i].c,-p[i].w);
}
int main()
{
	m=read();k=read();
	for(int i=1;i<=m;i++)
	{
		p[i].a=read();
		p[i].b=read();
		p[i].c=read();
	}
	sort(p+1,p+1+m,cmp1);
	for(int i=1,c=0;i<=m;i++)
	{
		c++;
		if(p[i].a!=p[i+1].a || p[i].b!=p[i+1].b || p[i].c!=p[i+1].c)
			p[++n]=p[i],p[n].w=c,c=0;
	}
	cdq(1,n);
	for(int i=1;i<=n;i++)
		cnt[p[i].ans+p[i].w-1]+=p[i].w;
	for(int i=0;i<m;i++)
		printf("%d\n",cnt[i]);
}
原创文章 430 获赞 14 访问量 1万+

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/105823005