Codeforces Beta Round #12 (Div 2 Only) D. Ball 题解

200 阅读2分钟

题目链接

思路

cdq分治的裸题。先把三个属性值离散化,进行cdq分治。设a[i].diea[i].die为能够杀死第ii个人的人数,即满足xj>xi,yj>yi,zj>zix_j>x_i,y_j>y_i,z_j>z_ijj的个数,如果a[i].die>0a[i].die>0,那么第ii个人就被杀死。但是实际上求出来的答案中存在xi=xj,yj>yi,zj>zix_i=x_j,y_j>y_i,z_j>z_i的情况(分治过程中并不能保证左边区间xx的最小值严格大于于左边区间最大值,存在二者相等的情况),因此要额外减去这些情况。

先以x,y,zx,y,z分别作为第一、第二、第三关键字排序,对xx值相等的某一段[l,r][l,r]单独考虑,也就是对这一段中的所有ii求出yj>yi,zj>ziy_j>y_i,z_j>z_ijj的个数,求的过程中用树状数组优化。此外还要考虑x,yx,y值均相等的情况,这些数据要一起维护答案,并一起维护进树状数组,否则就会计算到彼此的贡献。

这题用longlong会T。/kk

代码

#include<bits/stdc++.h>
#define lb(x) x&-x
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef int ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void say() {}
void say_() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
    int __=0;
    _=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            __=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        _=_*10+ch-48;
        ch=getchar();
    }
    _=__?-_:_;
    read(oth...);
}
template <typename T>
void Out(T _)
{
    if(_<0)
    {
        putchar('-');
        _=-_;
    }
    if(_>=10)
       Out(_/10);
    putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void say(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	say(oth...);
}
template <typename T, typename... T2>
inline void say_(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	say_(oth...);
}
/*#################################*/
const ll N=5E5+10;
ll n,m,ans;
ll t[N],vx[N],vy[N],vz[N];
struct Node{
	ll x,y,z,die;
	void pt()
	{
		say_(x,y,z,die);
		puts("");
	}
}a[N];
void add(ll x,ll val)
{
	while(x<=m)
	{
		t[x]+=val;
		x+=lb(x);
	}
}
ll query(ll x)
{
	ll ret=0;
	while(x)
	{
		ret+=t[x];
		x-=lb(x);
	}
	return ret;
}
void cdq(ll l,ll r)
{
	if(l==r)
		return;
	ll mid=(l+r)>>1;
	cdq(l,mid);
	cdq(mid+1,r);
	sort(a+l,a+mid+1,[](const Node &u,const Node &v)
	{
		if(u.y==v.y)
			return u.z>v.z;
		return u.y>v.y;
	});
	sort(a+mid+1,a+r+1,[](const Node &u,const Node &v)
	{
		if(u.y==v.y)
			return u.z>v.z;
		return u.y>v.y;
	});
	ll ind=l;
	rep(i,mid+1,r)
	{
		while(ind<=mid && a[ind].y>a[i].y)
		{
			add(a[ind].z,1);
			++ind;
		}
		a[i].die+=query(m)-query(a[i].z);
	}
	rep(i,l,ind-1)
		add(a[i].z,-1);
}
void print()
{
}
int main()
{
	read(n);
	rep(i,1,n)
	{
		read(a[i].x);
		vx[i]=a[i].x;
	}
	rep(i,1,n)
	{
		read(a[i].y);
		vy[i]=a[i].y;
	}
	rep(i,1,n)
	{
		read(a[i].z);
		vz[i]=a[i].z;
	}
	sort(vx+1,vx+n+1);
	ll nx=unique(vx+1,vx+n+1)-vx-1;
	sort(vy+1,vy+n+1);
	ll ny=unique(vy+1,vy+n+1)-vy-1;
	sort(vz+1,vz+n+1);
	ll nz=unique(vz+1,vz+n+1)-vz-1;
	m=nz;
	rep(i,1,n)
	{
		a[i].x=lower_bound(vx+1,vx+nx+1,a[i].x)-vx;
		a[i].y=lower_bound(vy+1,vy+ny+1,a[i].y)-vy;
		a[i].z=lower_bound(vz+1,vz+nz+1,a[i].z)-vz;
	}
	sort(a+1,a+n+1,[](const Node &u,const Node &v)
	{
		if(u.x==v.x)
		{
			if(u.y==v.y)
				return u.z>v.z;
			return u.y>v.y;
		}
		return u.x>v.x;
	});
	ll l=1,r=0;
	while(l<=n)
	{
		while(r<n && a[r+1].x==a[l].x)
			++r;
		rep(i,l,r)
		{
			ll ind=i;
			while(ind<r && a[i].y==a[ind+1].y)
				++ind;
			rep(j,i,ind)
				a[j].die-=query(m)-query(a[j].z);
			rep(j,i,ind)
				add(a[j].z,1);
			i=ind;
		}
		rep(i,l,r)
			add(a[i].z,-1);
		l=r+1;
	}
	cdq(1,n);
	rep(i,1,n)
		ans+=a[i].die>0?1:0;
	//print();
	say(ans);
}