您的位置:首页 > 其它

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 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

树套树 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: