题目大意
给n个三维坐标点,满足每维坐标都是1-n的排列,求三维偏序。
做法
注意到任意两个位置,都有一个位置有至少两维比另一个位置的对应两维大,于是可以容斥,那么只需要做二维偏序。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=2000000+10;
long long seed;
struct dong{
int x,y;
friend bool operator <(dong a,dong b){
return a.x<b.x;
}
} p[maxn],q[maxn];
int a[maxn],b[maxn],c[maxn],tree[maxn],id[maxn];
int i,j,k,l,t,n,m,mi;
ll ans;
bool czy;
long long Rand(){
return seed=((seed*19260817)^233333)&((1<<24)-1);
}
void gen(int *a){
fo(i,1,n) a[i]=i;
fo(i,1,n) swap(a[i],a[Rand()%i+1]);
}
int lowbit(int x){
return x&-x;
}
void change(int x){
while (x<=n){
tree[x]++;
x+=lowbit(x);
}
}
int query(int x){
int t=0;
while (x>0){
t+=tree[x];
x-=lowbit(x);
}
return t;
}
void work(){
//if (!czy) sort(p+1,p+n+1);
fo(i,1,n) q[i]=p[i];
fo(i,1,n) id[q[i].x]=i;
fo(i,1,n) p[i]=q[id[i]];
//register int i;
fo(i,1,n) tree[i]=0;
//mi=n+1;
/*fo(i,1,n){
ans+=(ll)query(p[i].y);
change(p[i].y);
}*/
i=1;
while (i+2<=n){
ans+=(ll)query(p[i].y);
change(p[i].y);
ans+=(ll)query(p[i+1].y);
change(p[i+1].y);
ans+=(ll)query(p[i+2].y);
change(p[i+2].y);
i+=3;
}
j=i;
fo(i,j,n){
ans+=(ll)query(p[i].y);
change(p[i].y);
}
}
bool cmpa(int x,int y){
return a[x]<a[y];
}
bool cmpb(int x,int y){
return b[x]<b[y];
}
int main(){
freopen("dalao.in","r",stdin);freopen("dalao.out","w",stdout);
scanf("%d",&n);
scanf("%lld",&seed);
gen(a);
scanf("%lld",&seed);
gen(b);
scanf("%lld",&seed);
gen(c);
/*fo(i,1,n) id[i]=i;
sort(id+1,id+n+1,cmpa);*/
/*fo(i,1,n)
fo(j,1,n)
if (a[i]<a[j]&&b[i]<b[j]&&c[i]<c[j]) ans++;*/
fo(i,1,n){
/*p[i].x=a[id[i]];
p[i].y=b[id[i]];*/
p[i].x=a[i];
p[i].y=b[i];
}
work();
//czy=1;
fo(i,1,n){
p[i].x=a[i];
//p[i].y=c[id[i]];
p[i].y=c[i];
}
work();
czy=0;
//sort(id+1,id+n+1,cmpb);
fo(i,1,n){
/*p[i].x=b[id[i]];
p[i].y=c[id[i]];*/
p[i].x=b[i];
p[i].y=c[i];
}
work();
ans-=(ll)n*(n-1)/2;
ans/=2;
printf("%lld\n",ans);
}