bzoj 3262 陌上花开 - CDQ分治 - 树状数组

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

HINT

1 <= N <= 100,000, 1 <= K <= 200,000

Source

  题目大意 三维偏序计数。

  首先偏序问题对于5维以下,通常有两种做法

  1)k-1层套树(我表示拒绝写这类程序,宁可写O(n2k)大暴力骗分,都不会去写这种"正解")

  2)CDQ分治 + (k - 2)层套树(比上面那种方法好多了)

  对于3维偏序,显然法2更优秀。可以参考上一道题(bzoj 1176)的做法。

  按c维第1关键字,m为第二关键字,s为第三关键字进行排序。

  对s进行CDQ分治。统计s在[l, mid]中的元素对[mid + 1, r]中的元素的贡献。用和上一道题同样的做法,将(c, m)看成一个点,左区间中的点看成修改操作,将点(c, m)的权值 + 1,右区间中的点看成查询一个子矩阵的点权和。然后做法一模一样。

  当l == r的时候就当成2维偏序问题,用树状数组水过。此时注意对于重复的判断。

Code

  1 /**
  2  * bzoj
  3  * Problem#3262
  4  * Accepted
  5  * Time:1628ms
  6  * Memory:9012k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 typedef bool boolean;
 11 
 12 typedef class Data {
 13     public:
 14         int val[3];
 15         int id;
 16         
 17         Data():val({0, 0, 0}), id(0) {        }
 18         
 19         friend boolean operator < (const Data& a, const Data &b) {
 20             for(int i = 1; i < 3; i++)
 21                 if(a.val[i] != b.val[i])
 22                     return a.val[i] < b.val[i];
 23             return a.val[0] < b.val[0];
 24         }
 25         
 26         boolean operator == (Data b) {
 27             return val[0] == b.val[0] && val[1] == b.val[1] && val[2] == b.val[2];
 28         }
 29 }Data;
 30 
 31 #define lowbit(x) ((x) & (-x))
 32 
 33 typedef class IndexedTree {
 34     public:
 35         int s;
 36         int *lis;
 37         
 38         IndexedTree():lis(NULL), s(0) {        }
 39         IndexedTree(int s):s(s) {
 40             lis = new int[(s + 1)];
 41             memset(lis, 0, sizeof(int) * (s + 1));
 42         }
 43         
 44         inline void add(int idx, int x) {
 45             for(; idx <= s; idx += lowbit(idx))
 46                 lis[idx] += x;
 47         }
 48         
 49         inline int getSum(int idx) {
 50             int rt = 0;
 51             for(; idx; idx -= lowbit(idx))
 52                 rt += lis[idx];
 53             return rt;
 54         }
 55 }IndexedTree;
 56 
 57 int n, K;
 58 vector<Data> ds;
 59 IndexedTree it;
 60 int *scores;
 61 int *cnts;
 62 
 63 inline void init() {
 64     scanf("%d%d", &n, &K);
 65     scores = new int[(n + 1)];
 66     cnts = new int[(n + 1)];
 67     memset(scores, 0, sizeof(int) * (n + 1));
 68     memset(cnts, 0, sizeof(int) * (n + 1));
 69     Data d;
 70     for(int i = 0; i < n; i++) {
 71         for(int j = 0; j < 3; j++)
 72             scanf("%d", &d.val[j]);
 73         d.id = i;
 74         ds.push_back(d);
 75     }
 76 }
 77 
 78 void CDQDividing(int l, int r, vector<Data> &q) {
 79     if(q.empty())    return;
 80     if(l == r)    {
 81         for(int i = 0, j; i < (signed)q.size(); i = j) {
 82             it.add(q[i].val[2], 1);
 83             for(j = i + 1; j < (signed)q.size() && q[j] == q[j - 1]; j++)
 84                 it.add(q[j].val[2], 1);
 85             int c = it.getSum(q[i].val[2]);
 86             for(int k = i; k < j; k++)
 87                 scores[q[k].id] += c - 1; 
 88         }
 89         for(int i = 0; i < (signed)q.size(); i++)
 90             it.add(q[i].val[2], -1);
 91         return;    
 92     }
 93     
 94     int mid = (l + r) >> 1;
 95     vector<Data> ql, qr;
 96     for(int i = 0; i < (signed)q.size(); i++) {
 97         if(q[i].val[0] <= mid)
 98             it.add(q[i].val[2], 1), ql.push_back(q[i]);
 99         else
100             scores[q[i].id] += it.getSum(q[i].val[2]), qr.push_back(q[i]);
101     }
102     
103     for(int i = 0; i < (signed)ql.size(); i++)
104         it.add(ql[i].val[2], -1);
105     
106     q.clear();
107     CDQDividing(l, mid, ql);
108     CDQDividing(mid + 1, r, qr);
109 }
110 
111 inline void solve() {
112     sort(ds.begin(), ds.end());
113     it = IndexedTree(K);
114 //    for(int i = 0; i < n; i++)
115 //        printf("%d %d %d\n", ds[i].val[0], ds[i].val[1], ds[i].val[2]);
116     CDQDividing(1, K, ds);
117     for(int i = 0; i < n; i++)
118         cnts[scores[i]]++;
119     for(int i = 0; i < n; i++)
120         printf("%d\n", cnts[i]);
121 }
122 
123 int main() {
124     init();
125     solve();
126     return 0;
127 }
posted @ 2017-07-29 17:33  阿波罗2003  阅读(147)  评论(0编辑  收藏  举报