bzoj3262 陌上花开

3262: 陌上花开

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 2808  Solved: 1258
[Submit][Status][Discuss]

Description

有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

1 <= N <= 100,000, 1 <= K <= 200,000

分析:cdq分治的模板题.大致思想是先对a排序,消除a的影响,实际上就相当于把a当作时间.接着就变成平面上有n个点,按照排序后的顺序依次询问有多少点在当前点左下方并插入当前的点.只涉及到插入和询问操作,并且能够离线,那么就用cdq分治,并用树状数组维护.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n,k,tot,ans[100010],cnt,c[200010];

struct node
{
    int a,b,c,d,f;
}e[100010],p[100010];

bool cmp(node a,node b)
{
    if (a.a == b.a && a.b == b.b)
    return a.c < b.c;
    if (a.a == b.a)
        return a.b < b.b;
    return a.a < b.a;
}

void add(int x,int v)
{
    while (x <= k)
    {
        c[x] += v;
        x += x & (-x);
    }
}

int query(int x)
{
    int res = 0;
    while (x)
    {
        res += c[x];
        x -= x & (-x);
    }
    return res;
}

void solve(int l,int r)
{
    if (l >= r)
        return;
    int mid = (l + r) >> 1;
    solve(l,mid);
    solve(mid + 1,r);
    cnt = l;
    int i = l,j = mid + 1;
    while (i <= mid || j <= r)
    {
        if (j > r || (i <= mid && e[i].b <= e[j].b))
        {
            add(e[i].c,e[i].d);
            p[cnt++] = e[i++];
        }
        else
        {
            e[j].f += query(e[j].c);
            p[cnt++] = e[j++];
        }
    }
    for (int i = l; i <= mid; i++)
        add(e[i].c,-e[i].d);
    for (int i = l; i <= r; i++)
        e[i] = p[i];
}

int main()
{
    scanf("%d%d",&n,&k);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
        e[i].d = 1;
    }
    tot = 1;
    sort(e + 1,e + 1 + n,cmp);
    for (int i = 2; i <= n; i++)
    {
        if (e[i].a == e[tot].a && e[i].b == e[tot].b && e[i].c == e[tot].c)
            e[tot].d++;
        else
            e[++tot] = e[i];
    }
    solve(1,tot);
    for (int i = 1; i <= tot; i++)
        ans[e[i].d + e[i].f - 1] += e[i].d;
    for (int i = 0; i < n; i++)
        printf("%d
",ans[i]);

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/8206457.html