三維偏序(陌上花開)

2022-05-15 09:50:36 字數 1877 閱讀 4828

這是一道模板題

可以使用bitset,cdq分治,k-dtree等方式解決。

有 n個元素,第 i個元素有 ai​、bi​、ci​三個屬性,設 f(i) 表示滿足 aj​≤ai​且 bj​≤bi​且 cj​≤ci​的 j 的數量。

對於 d∈[0,n),求 f(i)=d 的數量

輸入格式:

第一行兩個整數 n、k,分別表示元素數量和最大屬性值。

之後 n行,每行三個整數 ai​、bi​、ci

,分別表示三個屬性值。

輸出格式:

輸出 n 行,第 d+1 行表示 f(i)=d 的 i 的數量。

輸入樣例: 

10 3

3 3 3

2 3 3

2 3 1

3 1 1

3 1 2

1 3 1

1 1 2

1 2 2

1 3 2

1 2 1

輸出樣例: 

313

0101001

1≤n≤100000,1≤k≤200000

cdq分治,首先按對原序列進行三維排序,然後運用分治的思想,分治過程向下的時候保證a有序,分治過程回溯的時候保證b有序,某一分治中間態,我們只考慮mid左邊對mid右邊的影響(同在左邊或者同在右邊通過分治解決),因為mid左邊的a一定小於等於mid右邊的a,然後我們按照歸併排序的方法使得b也有序,這樣對於mid右邊的數來說,當前中間態有且僅有左邊的且b小於等於該數的數才能對它有貢獻,於是可以維護乙個樹狀陣列,在對b進行歸併排序的過程中,統計左邊的c出現的次數,並計算左邊的數對右邊的數的貢獻。

小細節:若兩個數的a,b,c值都相同,那麼如果直接進行cdq分治會導致相同數的貢獻不能全部計算的情況,因為cdq分治保證了每次計算左邊的數對右邊的數的貢獻,但是相同的數無論左右都對彼此有貢獻。所以要先去重,然後用乙個權值代表該數出現了多少次。

#includeusing

namespace

std;

const

int n = 2e5+50

;struct

ss

bool

operator == (const ss &s)const

};ss arr[n],ls[n];

pair

ls2[n];

intc[n];

void update(int pos,int

v)int sum(int

pos)

void print(int l,int

r)void cdq(int l,int r) //

分治 ;

ls[k++]=arr[i++];

}else

//右邊的數的b值比較小,那麼此時左邊的剩餘的數的b值一定都大於該數的b值,則此時對該數有貢獻的-

}while(i<=mid)

while(j<=r)

for(int i=0; i//

不能memset清空樹狀陣列

for(int i=l; i<=r; i++)arr[i]=ls[i];

//print(l,r);

}int ans[n]= ;

intmain()

else

}//for(int i=1;i<=pos;i++)printf("%d %d %d %d\n",arr[i].a,arr[i].b,arr[i].c,arr[i].value);

cdq(

1,pos);

for(int i=1; i<=pos; i++)

for(int i=0; i"

%d\n

",ans[i]);

return0;

}

view code

三維偏序 陌上花開

有 n 個元素,每個元素有三個屬性 a i b i c i 定義 f i 為滿足 a j a i 且 b j b i 且 c j c i 的 j 的個數 ans i sum f j i 求所有的 ans i 陌上花開,心憂梓桑。cdq 分治模板題 首先以 a 為關鍵字排序,省略一維 再以 b 為關鍵...

陌上花開(三維偏序)(cdq分治)

其實就是三位偏序的模板,cdq分治入門題。學習cdq分治請看 stdcall大佬的部落格 傳送門 排序來維護第一層,cdq維護一層,樹狀陣列維護一層,然後就沒有啦qwqwq include include include include include define maxn 100010 usin...

Luogu3810 三維偏序(陌上花開)

題目背景 這是一道模板題 可以使用bitset,cdq分治,k dtree等方式解決。題目描述有 n n 個元素,第 i role presentation style position relative i i個元素有ai a i bi b i ci c i三個屬性,設f i f i 表示滿足aj...