BZOJ3262陌上花開(三維偏序問題(CDQ分治+樹狀數組))+CDQ分治基本思想

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我私自搬他的博客的連接)

下面是題目:

Description

有n朵花,每朵花有三個屬性:花形(s)、顏色(c)、氣味(m),用三個整數表示。
如今要對每朵花評級,一朵花的級別是它擁有的美麗能超過的花的數量。
定義一朵花A比另外一朵花B要美麗,當且僅Sa>=Sb,Ca>=Cb,Ma>=Mb。
顯然,兩朵花可能有一樣的屬性。須要統計出評出每一個等級的花的數量。
 

Input

第一行爲N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分別表示花的數量和最大屬性值。
如下N行,每行三個整數si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的屬性

Output

包含N行,分別表示評級爲0...N-1的每級花的數量。

Sample Input

10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1

Sample Output

3
1
3
0
1
0
1
0
0
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 }
相關文章
相關標籤/搜索