COGS 2479. [HZOI 2016]偏序 [CDQ分治套CDQ分治 四維偏序]

傳送門php

 

給定一個有n個元素的序列,元素編號爲1~n,每一個元素有三個屬性a,b,c,求序列中知足i<j且ai<aj且bi<bj且ci<cj的數對(i,j)的個數。ios

 

對於100%的數據,1<=n<=50000,保證全部的ai、bi、ci分別組成三個1~n的排列。數組


 

$CDQ$分治套$CDQ$分治也不是很難嘛spa

對於本題,設四維$a,b,c,d$code

$Sort\ at\ a$blog

$CDQ(l,r)$排序

$\quad CDQ(l,mid)$遞歸

$\quad CDQ(mid+1,r)$ci

$\quad Merge_Sort\ at\ b$ 每一個元素標記屬於$[l,mid]\or\ [mid+1,r]$get

$\quad CDQ2(l,r)$

 

$CDQ2(l,r)$要作的就是按時間序維護一個二維點集$(c,d)$ 加點與詢問一個範圍內點的個數

和普通的三維偏序同樣,就是多了一個標記的限制(來自$CDQ$中$a$的限制,必須用標記不能判斷$a \le mid$,由於$CDQ2$是要遞歸下去的,$mid$就變了)

有一個時間序$b$和限制$a$,而後$c$歸併排序,$d$樹狀數組維護

 

完成啦!

 

#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);
}
相關文章
相關標籤/搜索