題意:
有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 ...