HDU Atlantis 线段树 表达区间

http://acm.hdu.edu.cn/showproblem.php?pid=1542

我的做法是把x轴的表示为线段,然后更新y

不考虑什么优化的话,开始的时候,把他们表达成线段,并按y排序,然后第一次加入线段树的应该就是最底下那条,然后第二条的时候,我们可以询问第二条那段区间,有多少是已经被覆盖的,然后把面积算上就可以。

所以如果区间都是整数,而且数值很少,那么就是线段树成段覆盖的问题了。但是这里是浮点数而且很大。

所以只能把它离散化。

这个时候线段树就不是连续的了,这里就有bug,问题就变成了怎么表达这颗线段树了。

思路是把它弄成L + 1 == R就是叶子节点,这样的话,每个节点都保存了一个区间了,

例如

要保存5、10、15、30

一般的线段树

      5、30

   5、10   15、30

  5    10    15         30

但是这样怎么表示[10, 15]这段区间呢?

所以把线段树变成

      5、30

    5、10   10、 30

        10、15  15、30

就行了。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>

int n;
const int maxn = 2e2 + 20;
struct node {
    int L, R;
    double x1, x2, y;
    int cover;
} seg[maxn << 2];
struct info {
    double x1, x2, y;
    int flag;
    bool operator < (const struct info & rhs) const {
        return y < rhs.y;
    }
} in[maxn];
double xx[maxn];
void build(int L, int R, int cur) {
    seg[cur].cover = 0;
    seg[cur].x1 = xx[L];
    seg[cur].x2 = xx[R];
    seg[cur].y = -1;
    seg[cur].L = L;
    seg[cur].R = R;
    if (L + 1 == R) { //两个节点作为一个叶子
        return;
    }
    int mid = (L + R) >> 1;
    build(L, mid, cur << 1);
    build(mid, R, cur << 1 | 1);
}
double upDate(int begin, int end, double y, int flag, int cur) {
    if (end <= seg[cur].L || begin >= seg[cur].R) return 0;
    if (seg[cur].L + 1 == seg[cur].R) {
        if (seg[cur].cover) {
            double ans = (seg[cur].x2 - seg[cur].x1) * (y - seg[cur].y);
            seg[cur].cover += flag;
            seg[cur].y = y;
            return ans;
        } else {
            seg[cur].cover += flag;
            seg[cur].y = y;
            return 0;
        }
    }
    double ans = upDate(begin, end, y, flag, cur << 1) + upDate(begin, end, y, flag, cur << 1 | 1);
    return ans;
}
void work() {
    int lenin = 0;
    int lenxx = 0;
    for (int i = 1; i <= n; ++i) {
        double xx1, xx2, yy1, yy2;
        scanf("%lf%lf%lf%lf", &xx1, &yy1, &xx2, &yy2);
        lenin++;
        in[lenin].x1 = xx1;
        in[lenin].x2 = xx2;
        in[lenin].y = yy1;
        in[lenin].flag = 1;
        lenxx++;
        xx[lenxx] = xx1;

        lenin++;
        in[lenin].x1 = xx1;
        in[lenin].x2 = xx2;
        in[lenin].y = yy2;
        in[lenin].flag = -1;
        lenxx++;
        xx[lenxx] = xx2;
    }
    sort(in + 1, in + 1 + lenin);
    sort(xx + 1, xx + 1 + lenxx);
    lenxx = unique(xx + 1, xx + 1 + lenxx) - (xx + 1);
    build(1, lenxx, 1);
    double ans = 0;
    const int root = 1;
    for (int i = 1; i <= lenxx; ++i) {
        printf("%f**\n", xx[i]);
    }
    for (int i = 1; i <= lenin; ++i) {
        int L = lower_bound(xx + 1, xx + 1 + lenxx, in[i].x1) - xx;
        int R = lower_bound(xx + 1, xx + 1 + lenxx, in[i].x2) - xx;
//        cout << L << " " << R << endl;
        ans += upDate(L, R, in[i].y, in[i].flag, root);
    }
    static int f = 0;
    printf("Test case #%d\n", ++f);
    printf("Total explored area: %0.2f\n", ans);
//    printf("%0.2f\n", ans);
}
int main() {
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    while (scanf("%d", &n) != EOF && n) {
        work();
        printf("\n");
    }
    return 0;
}

跪着看这篇blog想的

http://www.cnblogs.com/ka200812/archive/2011/11/13/2247064.html

时间: 2024-07-29 18:14:49

HDU Atlantis 线段树 表达区间的相关文章

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

HDU 1698 线段树(区间染色)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16255    Accepted Submission(s): 8089 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f

HDU 3308 线段树(区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3896    Accepted Submission(s): 1766 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

HDU 3308 线段树之区间合并

点击打开链接 题意:T组数据,每组n和m,代表n个数和m次操作,U代表将第a个数的值改为b,Q代表询问a~b区间的最长连续上升子序列的长度,严格上升的 思路:一看到询问多少次了这种,肯定是线段树不用想,问区间的最长上升,可以用区间合并,lnum代表从区间左第一个元素开始的最长上升长度,注意第一个元素必须有,rnum代表从区间必须有最后一个元素的最长上升子序列,,mmnum代表区间最长的上升子序列,而num现在存的并不是树了,而是数据,具体的还有注释 #include <stdio.h> #in

HDU 1542 Atlantis(线段树扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6788    Accepted Submission(s): 2970 Problem Description There are several ancient Greek

hdu 1542 Atlantis(线段树)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6899    Accepted Submission(s): 3022 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

HDU 1556 Color the ball(线段树:区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1556 题意: N个气球,每次[a,b]之间的气球涂一次色,统计每个气球涂色的次数. 思路: 这道题目用树状数组和线段树都可以,拿这道题来入门一下线段树的区间更新. 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 const int maxn = 1000

HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 8998    Accepted Submission(s): 3856 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin