• bzoj 3262 陌上花开


    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
    ", 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
    ", cnts[i]);
    121 }
    122 
    123 int main() {
    124     init();
    125     solve();
    126     return 0;
    127 }
  • 相关阅读:
    解题报告:luogu P1156
    解题报告:AT3605
    矩阵乘法与斐波那契数列
    九、模块
    八、异常
    七、文件处理
    六、对象和内存分析
    五、函数和内存分析
    四、控制语句
    三、序列
  • 原文地址:https://www.cnblogs.com/yyf0309/p/7256887.html
Copyright © 2020-2023  润新知