Problem
陌上花开
TimeLimit:20Sec
MemoryLimit:256MB
Description
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),用三个整数表示。
现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花a比另一朵花b要美丽,当且仅sa≥sb,ca≥cb,ma≥mb。
显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
第一行为N,K(1≤N≤105,1≤K≤2×105),分别表示花的数量和最大属性值。
以下N行,每行三个整数si,ci,mi(1≤si,ci,mi≤K),表示第i朵花的属性。
Output
包含N行,分别表示评级为0∼N−1的每级花的数量。
1 2 3 4 5 6 7 8 9 10 11
| 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
标签:CDQ分治
树状数组
三维偏序
Solution
三维偏序,CDQ分治裸题。
首先对x排序,记录每朵花排名。分治计算,对于区间[s,t],先按y值排序,再考虑该区间[s,mid]中的花对[mid+1,t]中的花产生的贡献,即若排名小于等于mid,将其z值加入树状数组;否则统计[s,mid]中y值比它小的花对它的贡献,即为树状数组中[1,z]的前缀和。
注意若有相同的一段花,则其答案一定是排在最后的这种花的答案。
Code
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
| #include <bits/stdc++.h> #define MAX_N 100000 #define MAX_M 200000 #define mid ((s+t)>>1) using namespace std; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } int n, m, tr[MAX_M+5], cnt[MAX_N+5]; struct node {int x, y, z, p, s;} a[MAX_N+5], b[MAX_N+5]; void inc(int p) {for (; p <= m; p += (p&-p)) tr[p]++;} void dec(int p) {for (; p <= m; p += (p&-p)) tr[p]--;} int sum(int p) {int ret = 0; for (; p; p -= (p&-p)) ret += tr[p]; return ret;} bool cmp(const node &a, const node &b) {return a.x == b.x ? (a.y == b.y ? (a.z < b.z) : a.y < b.y) : a.x < b.x;} bool operator == (node a, node b) {return a.x == b.x && a.y == b.y && a.z == b.z;} void CDQ(int s, int t) { if (s == t) return; CDQ(s, mid), CDQ(mid+1, t); for (int i = s, p1 = s, p2 = mid+1; i <= t; i++) b[i] = (p1 <= mid && (p2 > t || a[p1].y <= a[p2].y)) ? a[p1++] : a[p2++]; for (int i = s; i <= t; i++) a[i] = b[i]; for (int i = s; i <= t; i++) if (a[i].p <= mid) inc(a[i].z); else a[i].s += sum(a[i].z); for (int i = s; i <= t; i++) if (a[i].p <= mid) dec(a[i].z); } int main() { read(n), read(m); for (int i = 1; i <= n; i++) read(a[i].x), read(a[i].y), read(a[i].z); sort(a+1, a+n+1, cmp); for (int i = n-1; i >= 1; i--) if (a[i] == a[i+1]) a[i].s = a[i+1].s+1; for (int i = 1; i <= n; i++) a[i].p = i; CDQ(1, n); for (int i = 1; i <= n; i++) cnt[a[i].s]++; for (int i = 0; i < n; i++) printf("%d\n", cnt[i]); return 0; }
|