BZOJ3262陌上花开 树状数组+Treap

三个属性, 以第一个属性为关键字从小到大排序, 那么考虑一朵花的等级, 只需考虑排在其前面的花的其他属性(特殊情况是有相同的花,根据题意,对一段相同的花,以排在最后的一朵花的答案为准),那么后面的操作就不用考虑第一个属性了 第二三维可以用树状数组加Treap解决, 以每朵花第二属性数值作为位置(因为最大属性k < 2e5, 可以不用离散化, 直接用属性的数值对应树状数组中的下标), 树状数组的每个节点建一颗Treap, 这颗Treap里存的是相应区间里的花的第三个属性, 询问时类似于树状数组求前缀和, 依次将询问的花的位置的前面这一段分成不超过logk棵Treap对应的区间, 在这些区间里可以找出, 由于是以第二属性为位置插入到树状数组里的, 保证前面一段区间的第二属性都是不超过我们询问的花的第二属性, 只要在这不超过logk棵Treap里找出第三属性不超过询问的花的数量, 就是三个属性均不超过询问的花的三个属性的花的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 2e5 + 7, maxk = 2e5 + 7, maxnd = 1e6 + 7;
 
void readin(int &ret) {
    ret = 0; int f = 1; char ch = getchar();
    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9') ret *= 10, ret += ch - '0', ch = getchar();
    ret *= f;
}
 
struct flower {
    int s, c, m, id, ans;
    void read() {
        readin(s); readin(c); readin(m);
    }
} f[maxn];
bool cmp(const flower& a, const flower& b) {
    return a.s < b.s || (a.s == b.s && a.c < b.c) || (a.s == b.s && a.c == b.c && a.m < b.m);
}
 
bool ssame(const flower& a, const flower& b) {
    return a.s == b.s && a.c == b.c && a.m == b.m;
}
int n, k, siz, ans[maxn], root[maxn], sz[maxnd], val[maxnd], rnd[maxnd], cnt[maxnd], c[maxnd][2];
void update(int k) {
    sz[k] = sz[c[k][0]] + sz[c[k][1]] + cnt[k];
}
void rotate(int &k, int ch) {
    int t = c[k][ch]; c[k][ch] = c[t][ch ^ 1]; c[t][ch ^ 1] = k;
    sz[t] = sz[k]; update(k); k = t;
}
void insert(int &k, int x) {
    if(!k) {
        val[k = ++siz] = x;
        rnd[k] = rand();
        sz[k] = cnt[k] = 1;
        c[k][0] = c[k][1] = 0;
    } else if(val[k] == x) sz[k]++, cnt[k]++;
    else {
        sz[k]++;
        int d = val[k] < x;
        insert(c[k][d], x);
        if(rnd[c[k][d]] < rnd[k]) rotate(k, d);
    }
}
int find(int k, int x) {
    if(!k) return 0;
    if(val[k] == x) return sz[c[k][0]] + cnt[k];
    if(val[k] > x) return find(c[k][0], x);
    return sz[c[k][0]] + cnt[k] + find(c[k][1], x);
} //find(k, x)找出节点k为根的子树中, 权值不大于x的节点数量
#define lowbit(x) (x&-x)
void ins(int pos, int x) {
    while(pos <= k) {
        insert(root[pos], x);
        pos += lowbit(pos);
    }
}
int query(int pos, int x) {
    int ret = 0;
    while(pos > 0) {
        ret += find(root[pos], x);
        pos -= lowbit(pos);
    }
    return ret;
}
 
int top, stk[maxn], num[maxn];
int main() {
    readin(n); readin(k);
    for(int i = 1; i <= n; i++) f[i].read();
    sort(f + 1, f + n + 1, cmp);
    top = 0;
    for(int i = 1; i <= n; i++) {
        if(ssame(f[i], f[i + 1])) stk[++top] = i;//如果有相同的花, 先存到数组里, 直到处理了最后一朵这种花再更新前面的答案
        else {
            f[i].ans = query(f[i].c, f[i].m);
            while(top) f[stk[top--]].ans = f[i].ans;
        }
        ins(f[i].c, f[i].m);//询问了这朵花后再将这朵花插入树状数组中
    }
    for(int i = 1; i <= n; i++) num[f[i].ans]++;
    for(int i = 0; i <= n - 1; i++) printf("%d\n", num[i]);
    return 0;
}

  

posted @   using_namespace  阅读(360)  评论(0)    收藏  举报
编辑推荐:
· 为什么说方法的参数最好不要超过4个?
· C#.Net 筑基-优雅 LINQ 的查询艺术
· 一个自认为理想主义者的程序员,写了5年公众号、博客的初衷
· 大数据高并发核心场景实战,数据持久化之冷热分离
· 运维排查 | SaltStack 远程命令执行中文乱码问题
阅读排行:
· C#.Net筑基-优雅LINQ的查询艺术
· 博客园众包平台:诚征3D影像景深延拓实时处理方案(预算8-15万)
· Cursor生成UI,加一步封神
· 为什么说方法的参数最好不要超过4个?
· [原创]《C#高级GDI+实战:从零开发一个流程图》第04章:来个圆形,连线它!
点击右上角即可分享
微信分享提示