luogu3810 陌上花開 cdq分治

2022-04-30 01:03:19 字數 1768 閱讀 8228

求三維偏序

設三維為a,b,c。先對a排序,這樣i的偏序就只能然而排序的時候需要三個維度都判斷一遍,最後還要去重,不然會出現實際應該記答案的數出現在它後面的情況。

(排序用的函式裡不要寫類似於<=之類的東西啊..會出奇奇怪怪的問題的(re))

然後分治來做,我們在做區間[l,r]的時候,先去做[l,m]和[m+1,r]

之後左區間[l,m],右區間[m+1,r]都已經按照b排好序了,而且左右兩區間內部的答案已經統計過了,所以現在只要考慮左區間中滿足(右區間的數)的數量就好了。

那麼就也把[l,r]按照b排好序,在排的時候再用乙個權值樹狀陣列維護c,

也就是,如果這個點是左區間的點,就把它的c值對應的樹狀陣列中+=這個點的重複數(剛才去重了)

如果這個點是右區間的點,就詢問樹狀陣列中<=它的c值的數量,然後加到這個點的答案裡。

而且每次做的時候樹狀陣列都要清空,但不能用memset來清,複雜度有問題。(一直迷信memset的速度,結果一查告訴我也就比迴圈清快一倍??)

所以只要把剛才加過的再減回去就可以了。

複雜度$o(n*log_2n*log_2k)$

也可以cdq套cdq,然後不用樹狀陣列,複雜度是一樣的。

這樣一直套下去,k維的話複雜度也就是$o(n*log^_2n)$啦

#include#include

#include

#include

#include

#include

#include

#define ll long long int

#define inf 0x3f3f3f3f

#define lowbit(x) ((x)&(-(x)))

using

namespace

std;

const

int maxn=100010,maxk=200020

;ll rd()

while(c>='

0'&&c<='

9') x=x*10+c-'

0',c=getchar();

return x*neg;

}struct

nodeinp[maxn],num[maxn],tmp[maxn];

intinin,n,k;

inttr[maxk],cnt[maxn],siz[maxn],ans[maxn];

inline

bool cmp(node a,node b)

inline

void add(int x,int

y)inline

int query(int

x)void cdq(int l,int

r)else

}

while(q<=r)

for(int i=l;isiz[num[i].i]);

while(p<=m) tmp[++t]=num[p++];

memcpy(num+l,tmp+1,sizeof(node)*t);

}int

main()

sort(inp+1,inp+n+1,cmp);//

printf("ll");

for(i=1,j=0;i<=n;i++)

}n=j;

cdq(

1,n);

for(i=1;i<=n;i++) ans[cnt[i]]+=siz[i];

for(i=0;i"

%d\n

",ans[i]);

return0;

}

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...

P3810 陌上花開(CDQ分治)

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

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分治裡面,每...