大佬的难题

题目大意

给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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值