bzoj 3262 陌上花开 - CDQ分治 - 树状数组
2017-07-29 17:33
567 查看
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 33 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
31
3
0
1
0
1
0
0
1
HINT
1 <= N <= 100,000, 1 <= K <= 200,000Source
树套树 CDQ分治题目大意 三维偏序计数。
首先偏序问题对于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
/** * bzoj * Problem#3262 * Accepted * Time:1628ms * Memory:9012k */ #include <bits/stdc++.h> using namespace std; typedef bool boolean; typedef class Data { public: int val[3]; int id; Data():val({0, 0, 0}), id(0) { } friend boolean operator < (const Data& a, const Data &b) { for(int i = 1; i < 3; i++) if(a.val[i] != b.val[i]) return a.val[i] < b.val[i]; return a.val[0] < b.val[0]; } boolean operator == (Data b) { return val[0] == b.val[0] && val[1] == b.val[1] && val[2] == b.val[2]; } }Data; #define lowbit(x) ((x) & (-x)) typedef class IndexedTree { public: int s; int *lis; IndexedTree():lis(NULL), s(0) { } IndexedTree(int s):s(s) { lis = new int[(s + 1)]; memset(lis, 0, sizeof(int) * (s + 1)); } inline void add(int idx, int x) { for(; idx <= s; idx += lowbit(idx)) lis[idx] += x; } inline int getSum(int idx) { int rt = 0; for(; idx; idx -= lowbit(idx)) rt += lis[idx]; return rt; } }IndexedTree; int n, K; vector<Data> ds; IndexedTree it; int *scores; int *cnts; inline void init() { scanf("%d%d", &n, &K); scores = new int[(n + 1)]; cnts = new int[(n + 1)]; memset(scores, 0, sizeof(int) * (n + 1)); memset(cnts, 0, sizeof(int) * (n + 1)); Data d; for(int i = 0; i < n; i++) { for(int j = 0; j < 3; j++) scanf("%d", &d.val[j]); d.id = i; ds.push_back(d); } } void CDQDividing(int l, int r, vector<Data> &q) { if(q.empty()) return; if(l == r) { for(int i = 0, j; i < (signed)q.size(); i = j) { it.add(q[i].val[2], 1); for(j = i + 1; j < (signed)q.size() && q[j] == q[j - 1]; j++) it.add(q[j].val[2], 1); int c = it.getSum(q[i].val[2]); for(int k = i; k < j; k++) scores[q[k].id] += c - 1; } for(int i = 0; i < (signed)q.size(); i++) it.add(q[i].val[2], -1); return; } int mid = (l + r) >> 1; vector<Data> ql, qr; for(int i = 0; i < (signed)q.size(); i++) { if(q[i].val[0] <= mid) it.add(q[i].val[2], 1), ql.push_back(q[i]); else scores[q[i].id] += it.getSum(q[i].val[2]), qr.push_back(q[i]); } for(int i = 0; i < (signed)ql.size(); i++) it.add(ql[i].val[2], -1); q.clear(); CDQDividing(l, mid, ql); CDQDividing(mid + 1, r, qr); } inline void solve() { sort(ds.begin(), ds.end()); it = IndexedTree(K); // for(int i = 0; i < n; i++) // printf("%d %d %d\n", ds[i].val[0], ds[i].val[1], ds[i].val[2]); CDQDividing(1, K, ds); for(int i = 0; i < n; i++) cnts[scores[i]]++; for(int i = 0; i < n; i++) printf("%d\n", cnts[i]); } int main() { init(); solve(); return 0; }
相关文章推荐
- [CDQ分治] [树状数组] [BZOJ3262] 陌上花开
- 【BZOJ 3262】 陌上花开 CDQ分治 模板题
- BZOJ 3262 陌上花开、HDU 5618 Jam's problem again(三维偏序、cdq分治 + BIT)
- BZOJ 3262 陌上花开 (CDQ分治)
- BZOJ 3262 陌上花开(CDQ分治)
- BZOJ 3262 陌上花开 - CDQ分治
- Bzoj 3262: 陌上花开(CDQ分治)
- cdq分治入门--BZOJ3262: 陌上花开
- BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]
- bzoj 3262 陌上花开 【CDQ分治】
- bzoj 3262: 陌上花开(cdq分治)
- 【CDQ分治】 BZOJ3262 陌上花开
- BZOJ 3262 陌上花开 树套树 (CDQ分治)
- bzoj 3262: 陌上花开(cdq分治)
- BZOJ - 3262 陌上花开 CDQ分治 三维偏序
- BZOJ 3262 陌上花开 CDQ分治
- BZOJ 3262: 陌上花开 (CDQ分治)
- [BZOJ3262]陌上花开(cdq分治+讲解+小结)
- bzoj3262 陌上花开(CDQ分治)
- BZOJ 3262: 陌上花开 CDQ分治