陌上花开
有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
思路:
CDQ分治解决三维偏序的模板题。
推荐去这里学习:https://oi-wiki.org/misc/cdq-divide/
我写了两个版本,分别是第二维sort和归并排序。
代码(sort版本):
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline void getInt(int *p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
struct node {
int x, y, z;
int cnt;
int ans;
} a[maxn];
node b[maxn];
int Ans[maxn];
bool cmpx(node aa, node bb)
{
if (aa.x != bb.x) {
return aa.x < bb.x;
} else if (aa.y != bb.y) {
return aa.y < bb.y;
} else {
return aa.z < bb.z;
}
}
bool cmpy(node aa, node bb)
{
if (aa.y != bb.y) {
return aa.y < bb.y;
} else {
return aa.z < bb.z;
}
}
int n, k;
int tree[maxn];
int lowbit(int x)
{
return -x & x;
}
void add(int x, int v)
{
while (x < maxn) {
tree[x] += v;
x += lowbit(x);
}
}
int ask(int x)
{
int res = 0;
while (x) {
res += tree[x];
x -= lowbit(x);
}
return res;
}
void CDQ(int l, int r)
{
if (l == r) {
return ;
}
int mid = (l + r) >> 1;
CDQ(l, mid);
CDQ(mid + 1, r);
// 排序第二维度
sort(b + l, b + mid + 1, cmpy);
sort(b + mid + 1, b + r + 1, cmpy);
int pl = l;
int pr = mid + 1;
while (pr <= r) {
while (pl <= mid && b[pl].y <= b[pr].y) {
add(b[pl].z, b[pl].cnt);// 第三维度加入到树桩数组中
pl++;
}
b[pr].ans += ask(b[pr].z);// 树桩数组求前缀和的形式来求也满足第三维的偏序个数
pr++;
}
repd(i, l, pl - 1) {
add(b[i].z, -b[i].cnt);// 清空树桩数组。
}
}
int main()
{
//freopen("D:\\code\\text\\input.txt","r",stdin);
//freopen("D:\\code\\text\\output.txt","w",stdout);
du2(n, k);
repd(i, 1, n) {
du3(a[i].x, a[i].y, a[i].z);
}
int m = 0;
int cnt = 0;
sort(a + 1, a + 1 + n, cmpx);// 排序第一维度
repd(i, 1, n) {
cnt++;
// 把三个维度都相同的缩在一起
if (a[i].x != a[i + 1].x || a[i].y != a[i + 1].y || a[i].z != a[i + 1].z) {
b[++m] = a[i];
b[m].cnt = cnt;
cnt = 0;
}
}
CDQ(1, m);
repd(i, 1, m) {
Ans[b[i].ans + b[i].cnt - 1] += b[i].cnt;
}
repd(i, 0, n - 1) {
printf("%d\n", Ans[i] );
}
return 0;
}
inline void getInt(int *p)
{
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
} else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline void getInt(int *p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
struct node {
int x, y, z;
int cnt;
int ans;
} a[maxn];
node b[maxn];
node c[maxn];
int Ans[maxn];
bool cmpx(node aa, node bb)
{
if (aa.x != bb.x) {
return aa.x < bb.x;
} else if (aa.y != bb.y) {
return aa.y < bb.y;
} else {
return aa.z < bb.z;
}
}
bool cmpy(node aa, node bb)
{
if (aa.y != bb.y) {
return aa.y < bb.y;
} else {
return aa.z < bb.z;
}
}
int n, k;
int tree[maxn];
int lowbit(int x)
{
return -x & x;
}
void add(int x, int v)
{
while (x < maxn) {
tree[x] += v;
x += lowbit(x);
}
}
int ask(int x)
{
int res = 0;
while (x) {
res += tree[x];
x -= lowbit(x);
}
return res;
}
void CDQ(int l, int r)
{
if (l == r) {
return ;
}
int mid = (l + r) >> 1;
CDQ(l, mid);
CDQ(mid + 1, r);
int ql = l;
int qr = mid + 1;
repd(i, l, r) {
if (qr > r || (ql <= mid && b[ql].y <= b[qr].y)) {
add(b[ql].z, b[ql].cnt);
c[i] = b[ql++];
} else {
b[qr].ans += ask(b[qr].z);
c[i] = b[qr++];
}
}
ql = l;
qr = mid + 1;
repd(i, l, r) {
if (qr > r || (ql <= mid && b[ql].y <= b[qr].y)) {
add(b[ql].z, -b[ql].cnt);
ql++;
} else {
qr++;
}
}
repd(i, l, r) {
b[i] = c[i];
}
}
int main()
{
//freopen("D:\\code\\text\\input.txt","r",stdin);
//freopen("D:\\code\\text\\output.txt","w",stdout);
du2(n, k);
repd(i, 1, n) {
du3(a[i].x, a[i].y, a[i].z);
}
int m = 0;
int cnt = 0;
sort(a + 1, a + 1 + n, cmpx);// 排序第一维度
repd(i, 1, n) {
cnt++;
// 把三个维度都相同的缩在一起
if (a[i].x != a[i + 1].x || a[i].y != a[i + 1].y || a[i].z != a[i + 1].z) {
b[++m] = a[i];
b[m].cnt = cnt;
cnt = 0;
}
}
CDQ(1, m);
repd(i, 1, m) {
Ans[b[i].ans + b[i].cnt - 1] += b[i].cnt;
}
repd(i, 0, n - 1) {
printf("%d\n", Ans[i] );
}
return 0;
}
inline void getInt(int *p)
{
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
} else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}