记两条扫描线的题目 Rectangles(线段树),Intersecting Rectangles

3 篇文章 0 订阅
1 篇文章 0 订阅

Intersecting Rectangles

大致意思是给定n个矩形,问是否会存在相交
直接套扫描线
区分左边和右边,如果在还没抵消时发现区间已经有数值,说明会相交

AC Code:

// http://115.157.200.87/front/problem?problemId=1202
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>

using namespace std;
const int maxn = static_cast<const int>(4e5 + 100);

struct VerticalLine {
    int x, y1, y2, type;

    VerticalLine() = default;

    VerticalLine(int x, int y1, int y2, int type) : x(x), y1(y1), y2(y2), type(type) {}

    bool operator<(VerticalLine const &o) const { return x < o.x; }
};

class TreeArray {
public:
    long long treeArray[maxn]{};

    inline long lowBit(long x) {
        return x & (-x);
    }

    void add(long treeIndex, long value) {
        while (treeIndex <= maxn) {
            treeArray[treeIndex] += value;
            treeIndex += lowBit(treeIndex);
        }
    }

    long long sum(long x) {
        long long ans = 0;
        while (x != 0) {
            ans += treeArray[x];
            x -= lowBit(x);
        }
        return ans;
    }

    long long query(long l, long r) {
        if (l > r) {
            return 0;
        }
        return sum(r) - sum(l - 1);
    }

} treeArray;

vector<int> ys;
vector<VerticalLine> queries;
int n;

bool solve() {
    for (auto q: queries) {
        long l = lower_bound(ys.begin(), ys.end(), q.y1) - ys.begin() + 1;
        long r = lower_bound(ys.begin(), ys.end(), q.y2) - ys.begin() + 1;
        if (q.type == 1) {
            if (treeArray.query(l, r) > 0)
                return true;
            treeArray.add(l, 1);
            treeArray.add(r, 1);
        } else {
            treeArray.add(l, -1);
            treeArray.add(r, -1);
            if (treeArray.query(l, r) > 0)
                return true;
        }
    }
    return false;
}


int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    int x1, y1, x2, y2;
    for (int i = 0; i < n; ++i) {
        cin >> x1 >> y1 >> x2 >> y2;
        queries.emplace_back(x1, y1, y2, 1);
        queries.emplace_back(x2, y1, y2, -1);
        ys.push_back(y1);
        ys.push_back(y2);
    }
    sort(ys.begin(), ys.end());
    sort(queries.begin(), queries.end());
    if (solve())
        cout << '1';
    else cout << '0';
    return 0;
}

Rectangles

题目大意:求重叠奇数次区域的面积

这题麻烦一点,主要是线段树一开始写错了 调bug调了很久。。。

对每条边 先计算面积 然后进行区间异或

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>

using namespace std;
typedef long long ll;
const int maxn = static_cast<const int>(4e5 + 100);

vector<int> ys, xs;
namespace SegmentTree {
    int const maxn = static_cast<const int>(5e5 + 5);

    struct Node {
        int l, r;
        ll value, realLength;
        bool lazy;

        void _xor() {
            value = realLength - value;
        }
    } segTree[maxn * 3];

    void set(int i) {
        segTree[i]._xor();
        segTree[i].lazy ^= true;
    }

    void push_up(int i) { segTree[i].value = segTree[i << 1].value + segTree[(i << 1) | 1].value; }

    void push_down(int i) {
        if (!segTree[i].lazy) return;
        set(i << 1), set(i << 1 | 1);
        segTree[i].lazy = false;
    }

    /**
     * segTree[i].realLength = ys[r+1] - ys[l]
     *
     * @param i 1
     * @param l 0-based, inclusive.
     * @param r 0-based, inclusive.
     */
    void build(int i, int l, int r) {
        segTree[i].l = l;
        segTree[i].r = r;
        if (l == r) {
            segTree[i].realLength = ys[l + 1] - ys[l];
            return;
        }
//        if (l == r) {
//            segTree[i].realLength = -1;
//            return;
//        }
        int mid = (l + r) / 2;
        build(i << 1, l, mid);
        build((i << 1) | 1, mid + 1, r);
        segTree[i].realLength = segTree[i << 1].realLength + segTree[i << 1 | 1].realLength;
//        if (segTree[i << 1].realLength == 0) {
//            segTree[i].realLength = ys[r] - ys[l];
//        } else segTree[i].realLength = segTree[i << 1].realLength + segTree[i << 1 | 1].realLength;
    }


    /**
     * interval update.
     *
     * @param i 1
     * @param l 0-based, inclusive
     * @param r 0-based, inclusive.
     * @param val The value.
     */
    void update(int i, long l, long r) {
//        if (i == 6)
//            cout << "pause" << endl;
        if (segTree[i].l >= l && segTree[i].r <= r) {
            set(i);
            return;
        }
        push_down(i);
        int mid = (segTree[i].l + segTree[i].r) / 2;
        if (l <= mid) update(i << 1, l, r);
        if (r > mid) update((i << 1) | 1, l, r);
        push_up(i);
    }

}
struct VerticalLine {
    int x, y1, y2, type;

    VerticalLine() = default;

    VerticalLine(int x, int y1, int y2, int type) : x(x), y1(y1), y2(y2), type(type) {}

    bool operator<(VerticalLine const &o) const { return x < o.x; }
};

vector<VerticalLine> queries;
int n;

ll solve() {
    ll res = 0;
    ll lastX = queries[0].x;
    for (auto q: queries) {
        long l = lower_bound(ys.begin(), ys.end(), q.y1) - ys.begin();
        long r = lower_bound(ys.begin(), ys.end(), q.y2) - ys.begin();
//        if (q.type == 1) {
//        } else {
//
//        }
        res += abs(lastX - q.x) * SegmentTree::segTree[1].value;
        SegmentTree::update(1, l, r - 1);
//        cout << "curr " << q.y1 << " " << q.y2 << "    (l,r): " << l << " " << r << " " << SegmentTree::segTree[1].value
//             << endl;
        lastX = q.x;
    }
    return res;
}


int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    int x1, y1, x2, y2;
    for (int i = 0; i < n; ++i) {
        cin >> x1 >> y1 >> x2 >> y2;
        queries.emplace_back(x1, y1, y2, 1);
        queries.emplace_back(x2, y1, y2, -1);
        ys.push_back(y1);
        ys.push_back(y2);
        xs.push_back(x1);
        xs.push_back(x2);
    }
    sort(ys.begin(), ys.end());
    sort(queries.begin(), queries.end());
    SegmentTree::build(1, 0, ys.size() - 2);
    cout << solve() << endl;
    return 0;
}

线段树模板


class SegmentTree {
public:

    struct Node {
        int l, r;
        ll value, realLength;
        bool lazy;

        //todo: remove this if necessary
        void _xor() { value = realLength - value; }
    } segTree[maxn * 3];

    //TODO: modify this.
    void set(int i) {
        segTree[i]._xor();
        segTree[i].lazy ^= true;
    }

    //todo: modify this
    void push_up(int i) { segTree[i].value = segTree[i << 1].value + segTree[(i << 1) | 1].value; }

    void push_down(int i) {
        if (!segTree[i].lazy) return;
        set(i << 1), set(i << 1 | 1);
        segTree[i].lazy = false;
    }

    /**
     *
     * @param i 1
     * @param l 0-based, inclusive.
     * @param r 0-based, inclusive.
     */
    void build(int i, int l, int r) {
        segTree[i].l = l;
        segTree[i].r = r;
        if (l == r) {
            segTree[i].realLength = ys[l + 1] - ys[l];
            return;
        }
        int mid = (l + r) / 2;
        build(i << 1, l, mid);
        build((i << 1) | 1, mid + 1, r);
        segTree[i].realLength = segTree[i << 1].realLength + segTree[i << 1 | 1].realLength;
    }


    /**
     * interval update.
     *
     * @param i 1
     * @param l 0-based, inclusive
     * @param r 0-based, inclusive.
     * @param val The value.
     */
    void update(int i, long l, long r) {
        if (segTree[i].l >= l && segTree[i].r <= r) {
            set(i);
            return;
        }
        push_down(i);
        int mid = (segTree[i].l + segTree[i].r) / 2;
        if (l <= mid) update(i << 1, l, r);
        if (r > mid) update((i << 1) | 1, l, r);
        push_up(i);
    }

    ll query(int i, int l, int r) {
        if (l <= segTree[i].l && segTree[i].r <= r)
            return segTree[i].value;                //完全被包含的区间直接返回区间和
        if (r < segTree[i].l || segTree[i].r < l)
            return 0;                               //如果区间和查找区间没有交集,则直接返回0
        if (segTree[i].lazy)
            push_down(i);                           //这里要写在判断是否与查找区间有交集后面
        return query(i << 1, l, r) + query(i << 1 | 1, l, r);
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值