一层CDQ分治能将动态问题转化为静态问题, 对约束条件进行简化。
求解$n$维偏序。
对于每一个$n$元组$(a, b, c, d, ...)$。
首先按照a维排序, 问题就转化为了动态的$n-1$维偏序。
此时的$n - 1$元组$(b, c, d, ...)$包含查询/修改两个操作。
然后对序列进行CDQ分治,即保证$a$维/时间有序,
使其变成了静态的$n-1$偏序。
每次只需考虑左子区间的修改对右子区间的查询的影响。
嘿嘿嘿, 又是一个静态问题。
再按照b维排序, 又变成了动态的$n - 2$维偏序。
就这样套娃, 在问题成为2维偏序时直接解决就行了。
每套一次CDQ分治都会多个 log , 所以$k$维偏序时间复杂度应为$O(nlog^{k - 1}n)$
蒟蒻感觉CDQ套CDQ比内层数据结构如 BIT 的代码更加优美(逃
但好像要慢一些…… 下面就给出三维偏序的代码吧:)
1 #include <cstdio>
2 #include <algorithm>
3
4 const int N = 100000;
5
6 struct Node {
7 bool opt;
8 int a, b, c, Cnt, Ans, Loc;
9 } S1[N + 10], S2[N + 10], S3[N + 10];
10
11 int Tot[N + 10], n, L, k;
12
13 bool Cmp(Node, Node);
14 bool Equal(Node, Node);
15 void CDQ(int, int);
16 void cdq(int, int);
17
18 int main() {
19 scanf("%d%d", &n, &k);
20 for(int i = 1; i <= n; i ++)
21 scanf("%d%d%d", &S1[i].a, &S1[i].b, &S1[i].c);
22 std::sort(S1 + 1, S1 + 1 + n, Cmp);
23
24 int Count = 0;
25 for(int i = 1; i <= n; i ++) {
26 ++Count;
27 if(!Equal(S1[i], S1[i + 1]))
28 S2[++L] = S1[i], S2[L].Cnt = Count, Count = 0;
29 } CDQ(1, L);
30 for(int i = 1; i <= L; i ++)
31 Tot[S2[i].Ans + S2[i].Cnt - 1] += S2[i].Cnt;
32 for(int i = 0; i < n; i ++) printf("%d\n", Tot[i]);
33 return 0;
34
35 } bool Cmp(Node x, Node y) {
36 if(x.a != y.a) return x.a < y.a;
37 if(x.b != y.b) return x.b < y.b;
38 return x.c < y.c;
39
40 } bool Equal(Node x, Node y) {
41 if(x.a != y.a) return false;
42 if(x.b != y.b) return false;
43 if(x.c != y.c) return false;
44 return true;
45
46 } void CDQ(int l, int r) {
47 if(l >= r) return;
48 int Mid = (l + r) >> 1;
49 CDQ(l, Mid), CDQ(Mid + 1, r);
50 int p1, p2, nL;
51 p1 = nL = l, p2 = Mid + 1;
52 while(p1 <= Mid || p2 <= r)
53 if(p2 > r || p1 <= Mid && S2[p1].b <= S2[p2].b)
54 S2[p1].opt = 0, S1[nL++] = S2[p1++];
55 else S2[p2].opt = 1, S1[nL++] = S2[p2++];
56 for(int i = l; i <= r; i ++)
57 S2[i] = S3[i] = S1[i], S3[i].Loc = i;
58 cdq(l, r);
59
60 } void cdq(int l, int r) {
61 if(l >= r) return;
62 int Mid = (l + r) >> 1;
63 cdq(l, Mid), cdq(Mid + 1, r);
64 int p1, p2, nL, Cnt;
65 p1 = nL = l, p2 = Mid + 1, Cnt = 0;
66 while(p1 <= Mid || p2 <= r)
67 if(p2 > r || p1 <= Mid && S3[p1].c <= S3[p2].c) {
68 if(!S3[p1].opt) Cnt += S3[p1].Cnt;
69 S1[nL++] = S3[p1++];
70
71 } else {
72 if(S3[p2].opt) S2[S3[p2].Loc].Ans += Cnt;
73 S1[nL++] = S3[p2++];
74 }
75 for(int i = l; i <= r; i ++) S3[i] = S1[i];
76 }
将就着看看吧……同机房神犇大部分人大括号换行, 我码风要被喷死了……
以上只是蒟蒻拙见, 感谢大佬的阅读。
来源:oschina
链接:https://my.oschina.net/u/4401867/blog/4490227