1. 程式人生 > 實用技巧 >四維偏序

四維偏序

給定一個有n個元素的序列,元素編號為1~n,每個元素有三個屬性a,b,c,求序列中滿足i<j且ai<aj且bi<bj且ci<cj的數對(i,j)的個數。
對於1<=n<=50000,保證所有的ai、bi、ci分別組成三個1~n的排列。

試題連結

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=5e4+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n;
struct Operation{
    int a,b,c,d;
    bool flag;
}a[N],t1[N],t2[N];
int c[N];
inline int lowbit(int x){return x&-x;}
inline void add(int p,int v){for(;p<=n;p+=lowbit(p)) c[p]+=v;}
inline int sum(int p){
    int re=0;
    for(;p;p-=lowbit(p)) re+=c[p];
    return re;
}
int ans;
void CDQ2(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    CDQ2(l,mid);
	CDQ2(mid+1,r);
    int i=l,j=mid+1,p=l;
    Operation *a=t1,*t=t2;
    while(i<=mid||j<=r)
	{
        if(j>r||(i<=mid&&a[i].c<a[j].c))
		{
            if(a[i].flag) 
			   add(a[i].d,1);
            t[p++]=a[i++];
        }else
		{
            if(!a[j].flag) 
			    ans+=sum(a[j].d);
            t[p++]=a[j++];
        }
    }
    for(int i=l;i<=mid;i++) 
	    if(a[i].flag) add(a[i].d,-1);
    for(int i=l;i<=r;i++) 
	    a[i]=t[i];
}
void CDQ(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    CDQ(l,mid);
	CDQ(mid+1,r);
    int i=l,j=mid+1,p=l;
    Operation *t=t1;
    while(i<=mid||j<=r)
	{
        if(j>r||(i<=mid&&a[i].b<a[j].b)) 
		  (t[p++]=a[i++]).flag=1; // 來自左邊數列 
        else
		    (t[p++]=a[j++]).flag=0;  //來自右邊數列 
    }
    for(int i=l;i<=r;i++) 
	    a[i]=t[i];
    CDQ2(l,r);
}
int main(){
    freopen("partial_order.in","r",stdin);
    freopen("partial_order.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++) a[i].b=read();
    for(int i=1;i<=n;i++) a[i].c=read();
    for(int i=1;i<=n;i++) a[i].d=read(),a[i].a=i;
    CDQ(1,n);
    printf("%d",ans);
}