Tunnel Warfare HDU 1540 区间合并+最大最小值

Tunnel Warfare HDU 1540 区间合并+最大最小值

题意

D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点。

题解思路

参考的大佬博客

这里巧妙使用了最大值最小值来进行区间的查找。上一行是大佬的详细题解,真的很妙啊。

代码实现

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((t[rt].l+t[rt].r)>>1)
using namespace std;
const int maxn=5e4+7;
struct node{
    int l, r, maxx, minn; //维护区间内的最大最小值
}t[maxn<<2];
stack<int> des;
int n, m;
void pushup(int rt)
{
    t[rt].maxx=max(t[ls].maxx, t[rs].maxx);
    t[rt].minn=min(t[ls].minn, t[rs].minn);
}
void build(int rt, int l, int r)
{
    t[rt].l=l;
    t[rt].r=r;
    if(l==r)
    {
        t[rt].maxx=0; //最大值默认都是0
        t[rt].minn=n+1; //最小值默认都是n+1
        return ;
    }
    build(ls, l, mid);
    build(rs, mid+1, r);
    //pushup(rt);
    t[rt].maxx=max(t[ls].maxx, t[rs].maxx);
    t[rt].minn=min(t[ls].minn, t[rs].minn);
}
void destory(int rt, int x)
{
    if(t[rt].l==t[rt].r)
    {
        t[rt].maxx=t[rt].l;
        t[rt].minn=t[rt].l;
        return ;
    }
    if(x<=mid) destory(ls, x);
    else destory(rs, x);
    //pushup(rt);
    t[rt].maxx=max(t[ls].maxx, t[rs].maxx);
    t[rt].minn=min(t[ls].minn, t[rs].minn);
}
void rebuild(int rt, int x)
{
    if(t[rt].l==t[rt].r)
    {
        t[rt].maxx=0;
        t[rt].minn=n+1;
        return ;
    }
    if(x<=mid) rebuild(ls, x);
    else rebuild(rs, x);
    //pushup(rt);
    t[rt].maxx=max(t[ls].maxx, t[rs].maxx);
    t[rt].minn=min(t[ls].minn, t[rs].minn);
}
int query_max(int rt, int l, int r)
{
    if(l<=t[rt].l && t[rt].r <= r)
    {
        return t[rt].maxx;
    }
    int ans=0;
    if(l<=mid) ans=max(ans, query_max(ls, l, r));
    if(r>mid) ans=max(ans, query_max(rs, l, r));
    return ans;
}
int query_min(int rt, int l, int r)
{
    if(l<=t[rt].l && t[rt].r <= r)
    {
        return t[rt].minn;
    }
    int ans=0x3f3f3f3f;
    if(l<=mid) ans=min(ans, query_min(ls, l, r));
    if(r>mid) ans=min(ans, query_min(rs, l, r));
    return ans;
}
int main()
{
    char op[3];
    int x;
    while( scanf("%d%d", &n, &m)!=EOF)
    {
        while(!des.empty()) des.pop();
        build(1, 1, n);
        for(int i=1; i<=m; i++)
        {
            scanf("%s", op);
            if(op[0]=='D')
            {
                scanf("%d", &x);
                des.push(x);
                destory(1, x);
            }
            else if(op[0]=='Q')
            {
                scanf("%d", &x);
                int maxx=query_max(1, 1, x);
                int minn=query_min(1, x, n);
                if(maxx==minn)
                    printf("0\n");
                else printf("%d\n", minn-maxx-1);
            }
            else {
                x=des.top();
                des.pop();
                rebuild(1, x);
            }
        }
    }
    return 0;
 } 

原文地址:https://www.cnblogs.com/alking1001/p/11402741.html

时间: 2024-09-30 06:16:55

Tunnel Warfare HDU 1540 区间合并+最大最小值的相关文章

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 线段树区间合并

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 HDU - 1540

学习set,其他容器每次都要去sort(),除了堆(但其无法lower_bound) 题面 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 t

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;

I - Tunnel Warfare - hdu 1540(区间合并更新)

题意:在抗日战争期间,地道战在华北平原得到广泛的实施,一般而言,村庄通过一些隧道在一条线上连接,除了两端剩下的每个村庄都有两个相连. 侵略者会频繁的对这些村庄进行扫荡,并且摧他们的地道,当然八路军会把这一些已经被摧毁的村庄修复的,会优先修复最近被破坏的村庄. 分析:被这道题折磨了一上午啊,不过也学到了很多,尤其是这种涉及左右区间的. ********************************************************************* #include<std

HDU 1540 (区间合并)

#include<stdio.h> #include<stdlib.h> #include<string.h> #define maxn 50010 #define Lson root*2 #define Rson root*2+1 #define Max(a,b)(a>b?a:b) int ac[maxn]; struct ndoe {//lsum表示左区间的连续,rsum表示在右区间的连续,sum表示中间区间的连续; int L,R; int lsum,rsu

Tunnel Warfare HDU - 1540(线段树最长连续区间)

题意: 一条线上的点,D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点. 解析: 线段树结点 设置一个  lq记录区间左端点开始的最大连续个数,  rq 记录区间右端点开始的最大的连续个数 其它和原来一样即可 看代码吧... #include <iostream> #include <cstdio> #include <cstring> #include <stack> #include <queue>

I - Tunnel Warfare HDU - 1540 线段树最大连续区间

题意  :一段区间  操作1 切断点 操作2 恢复最近切断的一个点 操作3 单点查询该点所在最大连续区间 思路:  主要是push_up :  设区间x 为母区间  x<<1 ,x<<1|1分别为两个子区间 x的左端连续子段和 :当x<<1区间没有断开 也就是 x<<1 的最大连续子段ml ==tree[x<<1].r-tree[x<<1].l+1 等于区间长度时 x左端连续字段和tree[x].ll=tree[x<<1]