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