P3810 陌上花開(CDQ分治)

2021-10-01 18:29:40 字數 2156 閱讀 6757

題意:

有n

nn個元素,第i

ii個元素有a

ia_i

ai​,b

ib_i

bi​,c

ic_i

ci​三個屬性,設f(i

)f(i)

f(i)

表示滿足aj≤

ai

a_j≤a_i

aj​≤ai

​且bj≤b

ib_j≤b_i

bj​≤bi

​且cj≤c

ic_j≤c_i

cj​≤ci

​且j≠

ij≠i

j​=i的j

jj的數量,對於d∈[

0,n)

d∈[0,n)

d∈[0,n

),求f(i

)=

df(i)=d

f(i)=d

的數量題解:

其實三維偏序就是在二維偏序上加一維而已。

我們先按每個元素的a排序,然後第二維用歸併排序,第三維用樹狀陣列。

我們在歸併的時候考慮[l,mid]對[mid+1,r]的貢獻,因為我們已經按a排序過了,所以在對b排序的時候,無論a怎麼被打亂,[mid+1,r]的所有元素的a一定大於等於[l,mid]中所有元素的a,所以第二維是成立的。

在滿足前兩維都是有序時,第三位就能用樹狀陣列去統計答案了

注意題目中是有取等號的,所以我們要先將元素進行去重後,統計最終的答案

ac**:

#pragma gcc optimize(2)

#include

#include

using

namespace std;

using

namespace __gnu_cxx;

typedef

long

long ll;

const

int maxn =

1e5+10;

const

int mod =

1e9+7;

const

int inf =

0x3f3f3f3f

;struct nodea[maxn]

,b[maxn]

;int n,m,bit[maxn<<1]

,ans[maxn]

,cnt;

inline

bool

cmp(node x,node y)

namespace bit

inline

void

add(

int x,

int val)

inline

intquery

(int x,

int res=0)

}using

namespace bit;

inline

void

cdq(

int l,

int r)

while

(p<=mid)

add(a[p]

.z,a[p]

.cnt)

,b[tot++

]=a[p++];

while

(q<=r) a[q]

.res+

=query

(a[q]

.z),b[tot++

]=a[q++];

for(

int i=l;i<=mid;i++

)add

(a[i]

.z,-a[i]

.cnt)

;for

(int i=l;i<=r;i++

) a[i]

=b[i];}

signed

main()

cdq(

1,cnt)

;for

(int i=

1;i<=cnt;i++

) ans[a[i]

.res+a[i]

.cnt-1]

+=a[i]

.cnt;

for(

int i=

0;i)printf

("%d\n"

,ans[i]);

return0;

}

P3810 陌上花開 CDQ分治

傳送門 有n 個元素,第 i 個元素有 a i b i c i 三個屬性,設 f i 表示滿足 a j leq a i 且 b j leq b i且 c j leq c i的 j 的數量。對於 d in 0,n 求 f i d 的數量 cdq分治模板題,我們將第一維在主函式排序後,cdq分治裡面,每...

洛谷P3810 陌上花開(CDQ分治)

傳送門 題解 cdq分治模板題。一維排序,二維歸併,三維樹狀陣列。核心思想是分治,即計算左邊區間對右邊區間的影響。如下 include using namespace std typedef long long ll const int n 200005 int n,k,m struct node ...

luogu3810 陌上花開 cdq分治

求三維偏序 設三維為a,b,c。先對a排序,這樣i的偏序就只能然而排序的時候需要三個維度都判斷一遍,最後還要去重,不然會出現實際應該記答案的數出現在它後面的情況。排序用的函式裡不要寫類似於 之類的東西啊.會出奇奇怪怪的問題的 re 然後分治來做,我們在做區間 l,r 的時候,先去做 l,m 和 m ...