emmmm我能怎么说呢html
CDQ分治显然我无法写一篇完整的优秀的博客,由于我本身还不是很明白...c++
由于这玩意的思想实在是过短了:git
fateice如是说道:数组
若是说对于一道题目的离线操做,假设有n个操做学习
把n个操做分红两半,能够想到的是,假如说提出上面那半的修改操做,下面那半提出询问操做ui
那么这些修改操做对下面的询问操做显然是都产生了相同的影响的。spa
而后对于每一半的操做都这样递归下去,而后就有了CDQ分治处理问题的基本方法code
(图片来自fateice大爷的怕怕踢)htm
可是再往深处说我也不知道该怎么说,等研究的更深刻了再把CDQ分治的完整博客写出来吧blog
若是哪位路过的好心人看见了,记得催更
丢一篇大佬的上古博客:https://www.cnblogs.com/mlystdcall/p/6219421.html(但愿大佬不要diss我私自搬他的博客的连接)
下面是题目:
包含N行,分别表示评级为0...N-1的每级花的数量。
emmm读完题目后咱们显然的能够想到这是三维偏序的CDQ分治的基本题
而后就是对一维排序,对第二维CDQ分治,同时用树状数组处理第三维
但实际上我是把这题当成学习板子的板子题写的,因此我代码基本是学习别人的...
这题比较坑的地方是,对于属性值彻底相同的花来讲,各自互相美于对面,
这就好像你和你的几个克隆体站在一块儿,你比你的克隆体们聪明,你的克隆体们比你的克隆体们聪明,你的克隆体们又比你聪明...
或者说是,你把一份代码复制成数份,而后你的代码比你的代码优秀,你的代码又比你的代码优秀..
处理方式简单讲就是先把全部属性值相同的花都记一个数量,而后当作一种花处理,最后处理评级时再给加上...
总之具体处理过程仍是看代码吧...至少代码里有注释....
1 #include<bits/stdc++.h>
2 #define ll long long
3 #define uint unsigned int
4 #define ull unsigned long long
5 using namespace std; 6 const int maxn = 100010; 7 struct Query { 8 int s, c, m; 9 int num, sum; 10 bool operator < (const Query &A) const { 11 return c == A.c ? m < A.m : c < A.c; 12 } 13 bool operator != (const Query &A) const { 14 return s != A.s || c != A.c || m != A.m; 15 } 16 }a[maxn], q[maxn]; 17 int n, k, cnt = 0, top = 0; 18 int c[maxn << 1]; 19 int ans[maxn]; 20
21 inline int read() { 22 int x = 0, y = 1; 23 char ch = getchar(); 24 while(!isdigit(ch)) { 25 if(ch == '-') y = -1; 26 ch = getchar(); 27 } 28 while(isdigit(ch)) { 29 x = (x << 1) + (x << 3) + ch - '0'; 30 ch = getchar(); 31 } 32 return x * y; 33 } 34
35 inline bool cmp(Query x, Query y) {//按第一维排序
36 if(x.s == y.s && x.c == y.c) return x.m < y.m; 37 else if(x.s == y.s) return x.c < y.c; 38 return x.s < y.s; 39 } 40
41 inline int ask(int x) { 42 int res = 0; 43 for(; x; x -= (x & -x)) res += c[x]; 44 return res; 45 } 46
47 inline void add(int x, int y) { 48 for(; x <= k; x += (x & -x)) c[x] += y; 49 } 50
51 void solve(int l, int r) { 52 if(l == r) return; 53 int mid = l + r >> 1; 54 solve(l, mid), solve(mid + 1, r); 55 sort(q + l, q + mid + 1);//排序,让我sb的卡了会,由于不知道sort的排序是左闭右开
56 sort(q + mid + 1, q + r + 1); 57 int x = l; 58 for(int i = mid + 1; i <= r; ++i) {//用左边区间的答案导出右边区间的答案
59 while(x <= mid && q[x].c <= q[i].c) add(q[x].m, q[x].num), x++;//肯定了前两维的顺序时,将q[x].m赋上该品种的花的数量,方便右边区间查询
60 q[i].sum += ask(q[i].m);//查询
61 } 62 for(int i = l; i < x; ++i) add(q[i].m, -q[i].num);//还原树状数组
63 } 64
65 int main() { 66 n = read(), k = read(); 67 for(int i = 1; i <= n; ++i) 68 a[i].s = read(), a[i].c = read(), a[i].m = read(); 69 sort(a + 1, a + n + 1, cmp); 70 for(int i = 1; i <= n; ++i) { 71 cnt++; 72 if(a[i] != a[i + 1]) { 73 q[++top] = a[i]; 74 q[top].num = cnt;//对于某一品种花有多少个
75 cnt = 0; 76 } 77 } 78 solve(1, top); 79 for(int i = 1; i <= top; ++i) ans[q[i].sum + q[i].num - 1] += q[i].num; 80 //一朵花的评级=该朵花的美丽值超越的花的数量+属性相同的花的总量(包含本身)-1 81 //由于题目:定义一朵花A比另外一朵花B要美丽,当且仅Sa>=Sb,Ca>=Cb,Ma>=Mb。
82 for(int i = 0; i < n; ++i) printf("%d\n", ans[i]); 83 //评级可能有0的
84 return 0; 85 }