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