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

题意:在抗日战争期间,地道战在华北平原得到广泛的实施,一般而言,村庄通过一些隧道在一条线上连接,除了两端剩下的每个村庄都有两个相连。

侵略者会频繁的对这些村庄进行扫荡,并且摧他们的地道,当然八路军会把这一些已经被摧毁的村庄修复的,会优先修复最近被破坏的村庄。

分析:被这道题折磨了一上午啊,不过也学到了很多,尤其是这种涉及左右区间的。

*********************************************************************

#include<stdio.h>
#include<algorithm>
#include<stack>
using namespace std;

const int maxn = 50005;

struct node
{//sum代表区间种最大的连续区间,lsum代表左端能到达的最右端的个数
    int L, R, sum, lsum, rsum;
    int Mid(){return (L+R)/2;}
    int Len(){return (R-L+1);}
}a[maxn*4];

void Up(int r)
{
    a[r].lsum = a[r<<1].lsum, a[r].rsum = a[r<<1|1].rsum;

if(a[r<<1].lsum == a[r<<1].Len())
        a[r].lsum = a[r<<1].lsum + a[r<<1|1].lsum;
    if(a[r<<1|1].rsum == a[r<<1|1].Len())
        a[r].rsum = a[r<<1|1].rsum + a[r<<1].rsum;

a[r].sum = max(a[r].lsum, max(a[r].rsum, a[r<<1].rsum+a[r<<1|1].lsum));
}
void Build(int r, int L, int R)
{
    a[r].L = L, a[r].R = R;
    a[r].lsum = a[r].rsum = a[r].sum = a[r].Len();

if(L == R)return ;

Build(r<<1, L, a[r].Mid());
    Build(r<<1|1, a[r].Mid()+1, R);
}
void Insert(int r, int k, int e)
{
    if( a[r].L == a[r].R )
    {
        a[r].lsum = a[r].rsum = a[r].sum = e;
        return ;
    }

if(k <= a[r].Mid())
        Insert(r<<1, k, e);
    else
        Insert(r<<1|1, k, e);

Up(r);
}
int  Query(int r, int k)
{
    if(a[r].sum == 0)return 0;
    if(k < a[r].L+a[r].lsum)return a[r].lsum;//判断是否在左边
    if(k > a[r].R-a[r].rsum)return a[r].rsum;//判断是否在右边
    if(k > a[r<<1].R-a[r<<1].rsum && k < a[r<<1|1].L+a[r<<1|1].lsum)//判断是否在中间
        return a[r<<1].rsum + a[r<<1|1].lsum;

if(k <= a[r].Mid())
        return Query(r<<1, k);
    else
        return Query(r<<1|1, k);
}

int main()
{
    int N, M;

while(scanf("%d%d", &N, &M) != EOF)
    {
        int x; char s[10];
        stack<int> sta;

Build(1, 1, N);

while(M--)
        {
            scanf("%s", s);

if(s[0] == ‘D‘)
            {
                scanf("%d", &x);
                Insert(1, x, 0);
                sta.push(x);
            }
            else if(s[0] == ‘R‘ && sta.size())
            {
                Insert(1, sta.top(), 1);
                sta.pop();
            }
            else if(s[0] == ‘Q‘)
            {
                scanf("%d", &x);
                printf("%d\n", Query(1, x));
            }
        }
    }

return 0;

}

时间: 2024-10-12 09:47:06

I - Tunnel Warfare - hdu 1540(区间合并更新)的相关文章

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&l

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

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;

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]