思路
记第支队伍在第一场比赛中排名为,第二场为,第三场为。
考虑先按第一维排序,下标大的必定在第一场比赛中赢过下标小的,那么任意或都可以贡献答案,用树状数组计算两次二维偏序。但是其中会有重复贡献的答案,即对于某一对,存在,因此还要减去重复贡献的答案,即满足的数对的个数,是一个三位偏序问题,用cdq分治解决。
代码
#include<bits/stdc++.h>
#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 lb(x) x&-x;
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
inline void In(ll _,...)
{
va_list lis;
va_start(lis,_);
while(_--)
scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
va_list lis;
va_start(lis,_);
while(_--)
printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
va_list lis;
va_start(lis,_);
while(_--)
printf("%lld ",va_arg(lis,ll));
}
const ll N=2E5+10;
ll n,ans;
ll t[N];
struct Node{
ll x,y,z;
}a[N];
bool cmpx(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;
}
bool cmpy(const Node &u,const Node &v)
{
if(u.y==v.y)
return u.z>v.z;
return u.y>v.y;
}
void add(ll x,ll val)
{
while(x<=n)
{
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);
ll ind=l;
sort(a+l,a+mid+1,cmpy);
sort(a+mid+1,a+r+1,cmpy);
rep(i,mid+1,r)
{
while(ind<=mid && a[ind].y>a[i].y)
{
add(a[ind].z,1);
++ind;
}
ans-=query(n)-query(a[i].z);
}
rep(i,l,ind-1)
add(a[i].z,-1);
}
int main()
{
In(1,&n);
rep(i,1,n)
In(3,&a[i].x,&a[i].y,&a[i].z);
sort(a+1,a+n+1,cmpx);
rep(i,1,n)
{
ans+=query(n)-query(a[i].y);
add(a[i].y,1);
}
rep(i,1,n)
t[i]=0;
rep(i,1,n)
{
ans+=query(n)-query(a[i].z);
add(a[i].z,1);
}
rep(i,1,n)
t[i]=0;
cdq(1,n);
cout<<ans<<endl;
}