HDU - 1540 Tunnel Warfare(线段树 区间合并)

来源:互联网 发布:德约科维奇出轨知乎 编辑:程序博客网 时间:2024/05/29 16:33

题目大意:给你N个点,相邻的点连线。现在有3种操作
D x:破坏和x相连的线
Q x:x和几个点相连
R:修复刚被破坏的点的连接

解题思路:刚破坏的点可以用一个栈来存储。现在的问题是,怎么求一个点和几个点相连
我们维护区间的三个值,从最左端往右的连续没有被破坏的点数量lsum,从最右端开始往左的连续的没有被破坏的点的数量rsum,区间内最长的连续的没有被破坏的点的数量tsum

询问的时候可以这样做,首先先判断一下该点所属的区间的tsum,如果tsum为0,表示这个区间内没有点连通,那么返回的就是0了,如果tsum == (r - l + 1)表示所有的点都被连接起来了,那么返回(r - l + 1)
如果都不是的话,判断一下该点属于左区间还是右区间
假设属于左区间,那就要判断一下,该点是否在左区间的rsum范围内,如果在该范围内,表示该点和mid相连,所以还得查询一下右区间,找寻和mid + 1相连的点的数量。如果不在rsum的范围内,直接递归查找下去
右区间的情况和左区间的情况类似

#include <cstdio>#include <cstring>#include <algorithm>#include <stack>using namespace std;const int N = 50010 << 2;int lsum[N], rsum[N], tsum[N], mark[N];int n, m;void build(int u, int l, int r) {    lsum[u] = rsum[u] = tsum[u] = r - l + 1;    mark[u] = -1;    if (l == r) return ;    int mid = (l + r) >> 1;    build(u << 1, l, mid);    build(u << 1 | 1, mid + 1, r);}void Update(int u, int l, int r) {    lsum[u] = rsum[u] = tsum[u] = mark[u] ? 0 : r - l + 1;}void PushDown(int u, int l, int r) {    if (mark[u] == -1) return ;    mark[u << 1] = mark[u << 1 | 1] = mark[u];    mark[u] = -1;    int mid = (l + r) >> 1;    Update(u << 1, l, mid);    Update(u << 1 | 1, mid + 1, r);}void PushUp(int u, int l, int r) {    tsum[u] = max(max(tsum[u << 1], tsum[u << 1 | 1]), rsum[u << 1] + lsum[u << 1 | 1]);    lsum[u] = lsum[u << 1];    rsum[u] = rsum[u << 1 | 1];    int mid = (l + r) >> 1;    if (lsum[u] == mid - l + 1)        lsum[u] += lsum[u << 1 | 1];    if (rsum[u] == r - mid)        rsum[u] += rsum[u << 1];}void Modify(int u, int l, int r, int pos, int c) {    if (l == r) {        mark[u] = c;        Update(u, l, r);        return ;    }    PushDown(u, l, r);     int mid = (l + r) >> 1;    if (pos <= mid) Modify(u << 1, l, mid, pos, c);    else Modify(u << 1 | 1, mid + 1, r, pos, c);    PushUp(u, l, r);}int Query(int u, int l, int r, int pos) {    if (l == r || tsum[u] == 0 || tsum[u] == r - l + 1)         return tsum[u];    PushDown(u, l, r);    int mid = (l + r) >> 1;    if (pos <= mid) {        int tmp = mid - rsum[u << 1] + 1;        if (pos >= tmp) return Query(u << 1, l, mid, pos) + Query(u << 1 | 1, mid + 1, r, mid + 1);        else return Query(u << 1, l, mid, pos);    }    else {        int tmp = mid + lsum[u << 1 | 1];        if (pos <= tmp) return Query(u << 1 | 1, mid + 1, r, pos) + Query(u << 1, l, mid, mid);        else return Query(u << 1 | 1, mid + 1, r, pos);    }}void solve() {    stack<int> Stack;    build(1, 1, n);    char op[4];    int pos;    while (m--) {        scanf("%s", op);        if (op[0] == 'R') {            if (Stack.empty()) continue;            pos = Stack.top();            Stack.pop();            Modify(1, 1, n, pos, 0);        }        else if (op[0] == 'D') {            scanf("%d", &pos);            Stack.push(pos);            Modify(1, 1, n, pos, 1);        }        else {            scanf("%d", &pos);            printf("%d\n", Query(1, 1, n, pos));        }    }}int main() {    while (scanf("%d%d", &n, &m) != EOF)  solve();    return 0;}
0 0
原创粉丝点击