HDU 3255 题解 线段树+扫描线

Farming

Problem Description
You have a big farm, and you want to grow vegetables in it. You’re too lazy to seed the seeds yourself, so you’ve hired n people to do the job for you.
Each person works in a rectangular piece of land, seeding one seed in one unit square. The working areas of different people may overlap, so one unit square can be seeded several times. However, due to limited space, different seeds in one square fight each other – finally, the most powerful seed wins. If there are several “most powerful” seeds, one of them win (it does not matter which one wins).

There are m kinds of seeds. Different seeds grow up into different vegetables and sells for different prices.
As a rule, more powerful seeds always grow up into more expensive vegetables.
Your task is to calculate how much money will you get, by selling all the vegetables in the whole farm.

Input

The first line contains a single integer T (T <= 10), the number of test cases.
Each case begins with two integers n, m (1 <= n <= 30000, 1 <= m <= 3).
The next line contains m distinct positive integers pi (1 <= pi <= 100), the prices of each kind of vegetable.
The vegetables (and their corresponding seeds) are numbered 1 to m in the order they appear in the input.
Each of the following n lines contains five integers x1, y1, x2, y2, s, indicating a working seeded a rectangular area with lower-left corner (x1,y1), upper-right corner (x2,y2), with the s-th kind of seed.
All of x1, y1, x2, y2 will be no larger than 106 in their absolute values.

Output

For each test case, print the case number and your final income.

Sample Input

2
1 1
25
0 0 10 10 1
2 2
5 2
0 0 2 1 1
1 0 3 2 2

Sample Output

Case 1: 2500
Case 2: 16

Source

2009 Asia Regional Ningbo Online

题意
一群人在播种,每个种子占据一个单位(别太在意是什么单位)的正方形块。 但是有时候会有人将几个种子播种在一起,当两个种子在同一个正方形块里面的时候,他们就会相互争夺养分,价格高的植物会活下来。如果他们的价格相同,也得死得只剩一个。 现在给了你m种种子,和播种的正方形坐标,求你可以得到多少钱。

思路
求正方形体积并,高度为相应区间的种子价值,坐标很大需要离散化。考虑到求体积并比较复杂,而一共不超过3种种子,所以转化成求多层面积并。也就是将种子的价值p排序,依次选取>=p[k]的正方形求面积并,然后乘以p[k+1]-p[k]算体积(p[0]=0),即用种子的价值将体积分成多层。线段树用数组模拟,82行代码感觉挺简洁的。

#include <stdio.h>
#include <string.h>
#include <algorithm>

#define MAXN 30002
#define INIT(str) memset(str, 0, sizeof(str))

using namespace std;

struct seg
{
    int lx, rx, y, p, flag;
    bool operator <(const seg& b) const {return y<b.y;}
};

seg line[MAXN<<1];
int x[MAXN<<1];
int len[MAXN<<3];//线段累计长度
int sum[MAXN<<3];//多少条线段

void insert(int t, int l, int r, const seg* n)
{//由于每个x[i]被标记表示x[i-1]~x[i]被覆盖,所以lx并不用标记,下面的比较符号可能略显纠结
    if(x[l]>n->lx && x[r]<=n->rx)
        sum[t] += n->flag;
    else
    {
        int m = l + r >> 1;
        if(x[m] > n->lx)
            insert(t<<1, l, m, n);
        if(x[m] < n->rx)
            insert(t<<1|1, m+1, r, n);
    }
    if(sum[t])
        len[t] = x[r] - x[l-1];
    else if(l != r)
        len[t] = len[t<<1] + len[t<<1|1];
    else
        len[t] = 0;
}

int main ()
{
    int T, t, n, m, y1, y2, type, i, k, sx;
    scanf("%d", &T);
    int p[5] = {0};
    long long area, ans;
    for(t=1; t<=T && scanf("%d%d", &n, &m); t++)
    {
        for(i=1; i<=m && scanf("%d", p+i); i++);
        for(i=0, sx=0; i<n; i++, sx+=2)
        {
            scanf("%d%d%d%d%d", x+sx, &y1, x+sx+1, &y2, &type);
            line[i<<1].lx = line[i<<1|1].lx = x[sx];
            line[i<<1].rx = line[i<<1|1].rx = x[sx+1];
            line[i<<1].p = line[i<<1|1].p = p[type];
            line[i<<1].y = y1;
            line[i<<1|1].y = y2;
            line[i<<1].flag = 1;
            line[i<<1|1].flag = -1;
        }
        sort(p+1, p+m+1);
        sort(line, line+n+n);
        sort(x, x+sx);
        sx = unique(x, x+sx) - x;
        for(k=0, ans=0; k<m; k++)
        {
            INIT(len);
            INIT(sum);
            for(i=0, area=0, y1=0x7fffffff; i<n<<1; i++)
                if(line[i].p > p[k])
                {
                    if(line[i].y > y1)
                        area += (long long)len[1] * (line[i].y - y1);
                    insert(1, 1, sx-1, line+i);
                    y1 = line[i].y;
                }
            ans += area * (p[k+1] - p[k]);
        }
        printf("Case %d: %I64d\n", t, ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值