POJ--2892--Tunnel Warfare【线段树】区间合并

链接:http://poj.org/problem?id=2892

题意:有n个村庄排成一排,三种操作:

1. D x 摧毁村庄x

2. Q x 询问村庄x的最长一段没有被摧毁的村庄数量

3. R   恢复上一个被摧毁的村庄

思路:线段树区间合并,lsum记录当前节点往左的最长连续距离,rsum记录当前节点往右的最长连续距离。

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 50100
#define eps 1e-7
#define INF 0x3F3F3F3F      //0x7FFFFFFF
#define LLINF 0x3F3F3F3F3F3F3F3F    //0x7FFFFFFFFFFFFFFF
#define seed 1313131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

int sum[MAXN << 2], lsum[MAXN << 2], rsum[MAXN << 2];
int num[MAXN];
int n;
void pushup(int rt, int m){
    lsum[rt] = lsum[rt << 1];
    rsum[rt] = rsum[rt << 1 | 1];
    if(lsum[rt] == (m - (m >> 1)))    lsum[rt] += lsum[rt << 1 | 1];
    if(rsum[rt] == (m >> 1))    rsum[rt] += rsum[rt << 1];
    sum[rt] = max(lsum[rt << 1 | 1] + rsum[rt << 1], max(sum[rt << 1], sum[rt << 1 | 1]));
}
void build(int l, int r, int rt){
    sum[rt] = lsum[rt] = rsum[rt] = r - l + 1;
    if(l == r)  return ;
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
}
void update(int k, int c, int l, int r, int rt){
    if(l == r){
        sum[rt] = lsum[rt] = rsum[rt] = c;
        return ;
    }
    int m = (l + r) >> 1;
    if(k <= m)  update(k, c, lson);
    else    update(k, c, rson);
    pushup(rt, r - l + 1);
}
int query(int pos, int l, int r, int rt){
    if(l == r)  return sum[rt];
    int m = (l + r) >> 1;
    if(m >= pos){
        if(pos >= m - rsum[rt << 1] + 1)    return lsum[rt << 1 | 1] + rsum[rt << 1];
        else    return query(pos, lson);
    }
    else{
        if(pos <= m + lsum[rt << 1 | 1] + 1)    return lsum[rt << 1 | 1] + rsum[rt << 1];
        else    return query(pos, rson);
    }
}
stack<int>s;
int main(){
    int i, j, m, c;
    char str[5];
    while(scanf("%d%d", &n, &m) != EOF){
        build(1, n, 1);
        while(!s.empty())   s.pop();
        memset(num, 0, sizeof(int) * (n + 5));
        while(m--){
            scanf("%s", str);
            if(str[0] == 'R'){
                if(!s.empty()){
                    c = s.top();
                    s.pop();
                    num[c]--;
                    if(num[c] == 0) update(c, 1, 1, n, 1);
                }
            }
            else{
                scanf("%d", &c);
                if(str[0] == 'D'){
                    if(num[c] == 0) update(c, 0, 1, n, 1);
                    num[c]++;
                    s.push(c);
                }
                else{
                    if(num[c]){
                        puts("0");
                        continue;
                    }
                    printf("%d\n", query(c, 1, n, 1));
                }
            }
        }
    }
    return 0;
}
时间: 2024-08-27 10:51:48

POJ--2892--Tunnel Warfare【线段树】区间合并的相关文章

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

HDU 1540 Tunnel Warfare 线段树区间合并

Tunnel Warfare 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少 思路:一个节点的最大连续区间由(左儿子的最大的连续区间,右儿子的最大连续区间,左儿子的最大连续右区间+右儿子的最大连续左区间)决定 所以线段树的节点应该维护当前节点的最大连续左区间,最大连续右区间,和最大连续区间. 注意更新的时候,如果左儿子全满,父亲节点的左连续区间还要加上右儿子的左区间.反之同理. 查询的时候,可以剪枝,如果是叶子,或为空,或满,则不用往下查询. 查询

HDU 1540 Tunnel Warfare(线段树 区间合并 最大连续区间)

题意  有n个连在一起的地道  接下来有m个操作  D x 炸掉x号地道  炸掉后x所在的区间就不连续了  Q x 查询输出包括x的最大连续区间长度   R修复最后一个被炸的地道  注意输入R时可能并没有需要修复的地道 线段树的区间合并问题  线段树要维护3个信息 len  对应区间的最大连续长度 ll  对应区间最左端的一段连续长度 lr  对应区间最右端的一段连续长度 那么双亲节点的这些信息和孩子节点有什么关系呢  容易发现 双亲的len 是 左孩子的len 右孩子的len  左孩子的右端长

Tunnel Warfare 线段树 区间合并|最大最小值

During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly con

hdu 1540 Tunnel Warfare 线段树 区间合并

题意: 三个操作符 D x:摧毁第x个隧道 R x:修复上一个被摧毁的隧道,将摧毁的隧道入栈,修复就出栈 Q x:查询x所在的最长未摧毁隧道的区间长度. 1.如果当前区间全是未摧毁隧道,返回长度 2.如果在坐儿子的右区间或右儿子的左区间,返回这两个区间长度和 3.继续递归 #include <bits/stdc++.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std;

POJ 3667 Hotel 【线段树 区间合并 + Lazy-tag】

Hotel Time Limit: 3000MS Memory Limit: 65536K 链接:POJ 3667   Description The cows are journeying north to ThunderBay in Canada to gain cultural enrichment and enjoy a vacation on the sunnyshores of Lake Superior. Bessie, ever the competent travel agen

Poj 3667——hotel——————【线段树区间合并】

Hotel Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 13124   Accepted: 5664 Description The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie

POJ 3667 Hotel (线段树区间合并 )

Language: Default Hotel Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12417   Accepted: 5346 Description The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lak

POJ - 3667 Hotel(线段树区间合并)

题目链接 题意: 给定一个有$N$个车位的停车场(都在一条直线上),现在有有两种操作 $1.x $     要停连续的停$x$辆车,输出第一辆车停的位置(尽量靠前),不能就输出$0$: $2.x,d$ 从x位置开始开走连续的$d$辆车. 思路: 一个线段树区间和问题,而且满足区间可加性,就要用到区间合并. 1 /* 2 * Author: windystreet 3 * Date : 2018-08-15 10:29:55 4 * Motto : Think twice, code once.

POJ - 3667 - Hotel (线段树 - 区间合并)

题目传送:Hotel 思路:线段树,区间合并,区间替换,查询最左断点,看胡浩版本的线段树好几天了,今天看这个看了好久,慢慢来吧,具体都写在注释里了 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #inc