zoukankan      html  css  js  c++  java
  • 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**
    ", 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
    ", ++f);
        printf("Total explored area: %0.2f
    ", ans);
    //    printf("%0.2f
    ", ans);
    }
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        while (scanf("%d", &n) != EOF && n) {
            work();
            printf("
    ");
        }
        return 0;
    }
    View Code
    #include <bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    const int maxn = 1e3 + 20;
    struct Node {
        double x1, x2, y;
        int L, R;
        int cover;
    }seg[maxn << 2];
    vector<double> vc;
    int n;
    struct Info {
        double x1, x2, y;
        int cover;
        bool operator < (const struct Info & rhs) const {
            return y < rhs.y;
        }
    }fuck[maxn * 2];
    void build(int L, int R, int cur) {
        seg[cur].L = L, seg[cur].R = R;
        seg[cur].x1 = vc[L], seg[cur].x2 = vc[R];
        seg[cur].y = -inf;
        seg[cur].cover = 0;
        if (L + 1 == R) return;
        int mid = (L + R) >> 1;
        build(L, mid, cur << 1);
        build(mid, R, cur << 1 | 1);
    }
    double add(int x1, int x2, double y, int cover, int cur) {
        if (x2 <= seg[cur].L || x1 >= seg[cur].R) return 0;
        if (seg[cur].L + 1 == seg[cur].R) {
            if (seg[cur].cover) {
                double res = (y - seg[cur].y) * (seg[cur].x2 - seg[cur].x1);
                seg[cur].cover += cover;
                seg[cur].y = y; // 更新最大值y
                return res;
            } else {
                seg[cur].cover += cover;
                seg[cur].y = y;
                return 0;
            }
        }
        return add(x1, x2, y, cover, cur << 1) + add(x1, x2, y, cover, cur << 1 | 1);
    }
    void work() {
        vc.clear();
        vc.push_back(-1.0);
        int len = 0;
        for (int i = 1; i <= n; ++i) {
            double x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            ++len;
            fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = 1;
            ++len;
            fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1;
            vc.push_back(x1);
            vc.push_back(x2);
        }
        sort(vc.begin(), vc.end());
        sort(fuck + 1, fuck + 1 + len);
        build(1, vc.size(), 1);
        double ans = 0;
        for (int i = 1; i <= len; ++i) {
            int x1 = lower_bound(vc.begin(), vc.end(), fuck[i].x1) - vc.begin();
            int x2 = lower_bound(vc.begin(), vc.end(), fuck[i].x2) - vc.begin();
            ans += add(x1, x2, fuck[i].y, fuck[i].cover, 1);
        }
        static int f = 0;
        printf("Test case #%d
    ", ++f);
        printf("Total explored area: %.2f
    
    ", ans);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        while (cin >> n && n) work();
        return 0;
    }
    View Code

    跪着看这篇blog想的

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

    2017年8月15日 13:35:12

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

    只需要cover >= 2才计算

    #include <bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    const int maxn = 1e3 + 20;
    struct Node {
        double x1, x2, y;
        int L, R;
        int cover;
    }seg[maxn << 2];
    vector<double> vc;
    int n;
    struct Info {
        double x1, x2, y;
        int cover;
        bool operator < (const struct Info & rhs) const {
            return y < rhs.y;
        }
    }fuck[maxn * 2];
    void build(int L, int R, int cur) {
        seg[cur].L = L, seg[cur].R = R;
        seg[cur].x1 = vc[L], seg[cur].x2 = vc[R];
        seg[cur].y = -inf;
        seg[cur].cover = 0;
        if (L + 1 == R) return;
        int mid = (L + R) >> 1;
        build(L, mid, cur << 1);
        build(mid, R, cur << 1 | 1);
    }
    double add(int x1, int x2, double y, int cover, int cur) {
        if (x2 <= seg[cur].L || x1 >= seg[cur].R) return 0;
        if (seg[cur].L + 1 == seg[cur].R) {
            if (seg[cur].cover >= 2) {
                double res = (y - seg[cur].y) * (seg[cur].x2 - seg[cur].x1);
                seg[cur].cover += cover;
                seg[cur].y = y; // 更新最大值y
                return res;
            } else {
                seg[cur].cover += cover;
                seg[cur].y = y;
                return 0;
            }
        }
        return add(x1, x2, y, cover, cur << 1) + add(x1, x2, y, cover, cur << 1 | 1);
    }
    void work() {
        vc.clear();
        vc.push_back(-1.0);
        int len = 0;
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            double x1, y1, x2, y2;
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            ++len;
            fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = 1;
            ++len;
            fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1;
            vc.push_back(x1);
            vc.push_back(x2);
        }
        sort(vc.begin(), vc.end());
        sort(fuck + 1, fuck + 1 + len);
        build(1, vc.size(), 1);
        double ans = 0;
        for (int i = 1; i <= len; ++i) {
            int x1 = lower_bound(vc.begin(), vc.end(), fuck[i].x1) - vc.begin();
            int x2 = lower_bound(vc.begin(), vc.end(), fuck[i].x2) - vc.begin();
            ans += add(x1, x2, fuck[i].y, fuck[i].cover, 1);
        }
        printf("%.2f
    ", ans);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        int t;
        scanf("%d", &t);
        while (t--) work();
        return 0;
    }
    View Code

    http://codeforces.com/contest/610/problem/D

    这题要用到另一种方法

    不然TLE

    这题是把线条表达成一个长度大小是1的矩形

    如果矩形表达成[x1, x2],那么边长应该是x2 - x1 + 1(因为在直线的意义下所有点都覆盖了)

    所以要把矩形表达成[x1 - 1, x2],同时要注意统一化,就是水平的和垂直的都是按照这个方向改。

    x轴要固定向左端减小。

    #include <bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    const int maxn = 400000 + 20;
    struct Info {
        int x1, x2, cover;
        LL y;
        bool operator < (const struct Info & rhs) const {
            return y < rhs.y;
        }
    } fuck[maxn];
    vector<int> vc;
    struct Node {
        int L, R;
        int x1, x2, y;
        int cover;
    }seg[maxn << 2];
    void build(int L, int R, int cur) {
        seg[cur].L = L, seg[cur].R = R;
        seg[cur].x1 = vc[L], seg[cur].x2 = vc[R];
        seg[cur].y = 0;
        seg[cur].cover = 0;
        if (L + 1 == R) return;
        int mid = (L + R) >> 1;
        build(L, mid, cur << 1);
        build(mid, R, cur << 1 | 1);
    }
    void pushUp(int cur) {
        if (seg[cur].cover) {
            seg[cur].y = vc[seg[cur].R] - vc[seg[cur].L];
        } else if (seg[cur].L + 1 == seg[cur].R) {
            seg[cur].y = 0;
        } else {
            seg[cur].y = seg[cur << 1].y + seg[cur << 1 | 1].y;
        }
    }
    void add(int be, int en, int y, int cover, int cur) {
        if (seg[cur].L > en || seg[cur].R < be) return;
        if (seg[cur].L >= be && seg[cur].R <= en) {
            seg[cur].cover += cover;
            pushUp(cur);
            return;
        }
        add(be, en, y, cover, cur << 1);
        add(be, en, y, cover, cur << 1 | 1);
        pushUp(cur);
    }
    void work() {
        vc.clear();
        vc.push_back(-inf);
        int n, len = 0;
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            int x1, y1, x2, y2;
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            if (x1 == x2) {
                if (y1 > y2) swap(y1, y2);
                ++len;
                fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1 - 1, fuck[len].cover = 1;
                ++len;
                fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1;
                vc.push_back(x1 - 1);
                vc.push_back(x2);
            } else {
                if (x1 > x2) swap(x1, x2);
                ++len;
                fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = -1;
                ++len;
                fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1 - 1, fuck[len].cover = 1;
                vc.push_back(x1 - 1);
                vc.push_back(x2);
            }
        }
        sort(vc.begin(), vc.end());
    //    vc.erase(unique(vc.begin(), vc.end()), vc.begin());
        sort(fuck + 1, fuck + 1 + len);
        build(1, vc.size(), 1);
        LL ans = 0;
        for (int i = 1; i < len; ++i) {
            int x1 = lower_bound(vc.begin(), vc.end(), fuck[i].x1) - vc.begin();
            int x2 = lower_bound(vc.begin(), vc.end(), fuck[i].x2) - vc.begin();
            add(x1, x2, fuck[i].y, fuck[i].cover, 1);
            ans += seg[1].y * (fuck[i + 1].y - fuck[i].y);
        }
        cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code

    求解区间

    [L1, R1]、[L2, R2].....这样区间的,线段树的叶子节点一定要维护两个值。才算是叶子节点。就是上面所说的

    主要是:因为这些区间不是连续的。

    例如

    要保存5、10、15、30

    一般的线段树

          5、30

       5、10   15、30

      5    10    15         30

    是无法得到a[4] - a[1] = 25的区间长度的。

    如果你直接跑线段树,就是左右儿子的总和加上来。这样就是10 - 5 + 30 - 15 = 20

    漏了一段,那一段?10--15

    所以表示成

               5 10 15 30

      5  10            10 15  30

                        10 15      15 30

    是一种好的选择,因为这和一般的线段树不同,一般的线段树都是连续的整数,现在是分散的。所以要这样来代表

    #include <bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    #define lson L, mid, cur << 1
    #define rson mid, R, cur << 1 | 1
    #define root 1, all, 1
    const int maxn = 600000 + 20;
    struct Info {
        int x1, x2, cover;
        LL y;
        bool operator < (const struct Info & rhs) const {
            return y < rhs.y;
        }
    } fuck[maxn];
    vector<int> vc;
    LL seg[maxn << 2], cov[maxn << 2];
    void pushUp(int cur, int L, int R) {
        if (cov[cur]) seg[cur] = vc[R] - vc[L];
        else if (L + 1 == R) seg[cur] = 0;
        else {
            seg[cur] = seg[cur << 1] + seg[cur << 1 | 1];
        }
    }
    void upDate(int be, int en, int val, int L, int R, int cur) {
        if (L > en || R < be) return;
        if (L >= be && R <= en) {
            cov[cur] += val;
            pushUp(cur, L, R);
            return;
        }
        if (L + 1 == R) return;  //必须的
        int mid = (L + R) >> 1;
        upDate(be, en, val, lson);
        upDate(be, en, val, rson); //维护两个节点
        pushUp(cur, L, R);
    }
    void work() {
        vc.clear();
        vc.push_back(-inf);
        int n, len = 0;
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            int x1, y1, x2, y2;
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            if (x1 == x2) {
                if (y1 > y2) swap(y1, y2);
                ++len;
                fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1 - 1, fuck[len].cover = 1;
                ++len;
                fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1;
                vc.push_back(x1 - 1);
                vc.push_back(x2);
            } else {
                if (x1 > x2) swap(x1, x2);
                ++len;
                fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = -1;
                ++len;
                fuck[len].x1 = x1 - 1, fuck[len].x2 = x2, fuck[len].y = y1 - 1, fuck[len].cover = 1;
                vc.push_back(x1 - 1);
                vc.push_back(x2);
            }
        }
    //    for (int i = 1; i <= n; ++i) {
    //        int x1, y1, x2, y2;
    //        cin >> x1 >> y1 >> x2 >> y2;
    //        vc.push_back(x1);
    //        vc.push_back(x2);
    //        ++len;
    //        fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y1, fuck[len].cover = 1;
    //        ++len;
    //        fuck[len].x1 = x1, fuck[len].x2 = x2, fuck[len].y = y2, fuck[len].cover = -1;
    //    }
        //上面注释只是普通的矩形面积交。
        sort(vc.begin(), vc.end());
        sort(fuck + 1, fuck + 1 + len);
        int all = vc.size() - 1; //只能去到-1
        LL ans = 0;
        for (int i = 1; i < len; ++i) {
            int x1 = lower_bound(vc.begin(), vc.end(), fuck[i].x1) - vc.begin();
            int x2 = lower_bound(vc.begin(), vc.end(), fuck[i].x2) - vc.begin();
            upDate(x1, x2, fuck[i].cover, root);
    //        cout << seg[1] << endl;
            ans += seg[1] * (fuck[i + 1].y - fuck[i].y);
        }
        cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    
    
    
    
    矩形面积交数据
    2
    1 0 3 3
    2 1 4 4
  • 相关阅读:
    (转)A*算法详解及习题
    BZOJ1444[Jsoi2009]有趣的游戏——AC自动机+概率DP+矩阵乘法
    交通——set+dsu on tree
    [Codeforces1132G]Greedy Subsequences——线段树+单调栈
    BZOJ4482[Jsoi2015]套娃——贪心+set
    BZOJ4477[Jsoi2015]字符串树——可持久化trie树
    BZOJ4475[Jsoi2015]子集选取——递推(结论题)
    [UOJ86]mx的组合数——NTT+数位DP+原根与指标+卢卡斯定理
    BZOJ2428[HAOI2006]均分数据——模拟退火
    BZOJ4712洪水——动态DP+树链剖分+线段树
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6067933.html
Copyright © 2011-2022 走看看