poj2892 同hdu1540 Tunnel Warfare 线段树

本文介绍了一种使用线段树解决地道战模拟问题的方法。通过维护三个值(ls, lr, ms)来更新和查询区间内连续的地道长度。利用栈记录被破坏的地道,以便进行回溯修复。

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

题意:在抗日时期,我方经常采用地道战,地雷战,麻雀战来袭扰日军。
 现在n个村子一开始是全部联通的,假设成一条直线。
 给出3种操作  D x   x村庄的地道被日本鬼子炸毁 (炸毁之后地道无法相连)
    Q x   问有与x相连的村庄最长的长度 假设一个村为一个长度单位
    R     修复日本鬼子最近一个炸毁的村庄的地道 (最近指时间最近)
做法:用线段树来维护三个值,ls,lr,ms,   ls是对一个区间从最左端起连续的地道长度
rs是对一个区间从最右端起连续的地道长度
ms是对一个区间最长的连续的地道长度
用栈来存储日本鬼子炸毁的地道,以便后续修复。
询问一次查找一次。输出结果

代码:

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <deque>
#include <math.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <functional>
#define mem(a) memset(a,0,sizeof(a));
#define mem_1(a) memset(a,-1,sizeof(a));
#define sf(a) scanf("%d",&a)
#define sff(a,b) scanf("%d%d",&a,&b)
#define sfff(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define lson l,mid,root << 1
#define rson mid+1,r,root << 1|1
const int INF = 0x7FFFFFFF;
const int MAXN = 50100;
const double PI = acos(-1.0);
const double esp = 1e-10;
using namespace std;
struct node
{
    int l,r,ls,rs,ms;
    int mid()
    {
        return (l+r)>>1;
    }
}Tree[MAXN<<2];
int s[MAXN<<1];
void build_tree(int l,int r,int root)
{
    Tree[root].l = l;
    Tree[root].r = r;
    Tree[root].ls = Tree[root].rs = Tree[root].ms = r - l +1;
    if(l == r) return ;
    int mid = Tree[root].mid();
    build_tree(lson);
    build_tree(rson);
}
void updata_tree(int t,int root,int k)
{
    if(Tree[root].l == Tree[root].r)
    {
        if(k == 1)
            Tree[root].ls = Tree[root].rs = Tree[root].ms = 1;
        else
            Tree[root].ls = Tree[root].rs = Tree[root].ms = 0;
        return ;
    }
    int mid = Tree[root].mid();
    if(t <= mid) updata_tree(t,root<<1,k);
    else updata_tree(t,root<<1|1,k);
    Tree[root].ls = Tree[root<<1].ls;
    Tree[root].rs = Tree[root<<1|1].rs;
    Tree[root].ms = max(max(Tree[root<<1].ms,Tree[root<<1|1].ms),
                        Tree[root<<1].rs + Tree[root<<1|1].ls);
    if(Tree[root << 1].ls == Tree[root << 1].r - Tree[root<<1].l +1)
    {
        Tree[root].ls = Tree[root<<1].ls+Tree[root <<1|1].ls;
    }
    if(Tree[root << 1|1].rs == Tree[root<<1|1].r - Tree[root<<1|1].l +1)
    {
        Tree[root].rs = Tree[root<<1|1].rs + Tree[root<<1].rs;
    }
}
int Query(int root,int t)
{
    if(Tree[root].l == Tree[root].r ||
        Tree[root].ms==0 ||
        Tree[root].ms == Tree[root].r - Tree[root].l +1)
        return Tree[root].ms;
    int mid = Tree[root].mid();
    if(t<=mid)
    {
        if(t >= Tree[root << 1].r - Tree[root<<1].rs +1)
            return Query(root << 1,t) + Query(root<<1|1,mid+1);
        else
            return Query(root << 1,t);
    }
    else
    {
        if(t<=Tree[root<<1|1].l + Tree[root<<1|1].ls-1)
            return Query(root<<1|1,t) + Query(root<<1,mid);
        else
            return Query(root<<1|1,t);
    }
}
int main()
{
    int i,j,x,n,m,top;
    char c[2];
    while(~sff(n,m))
    {
        top = 0;
        build_tree(1,n,1);
        while(m--)
        {
            scanf("%s",c);
            if(c[0] == 'D')
            {
                sf(x);
                s[top++] = x;
                updata_tree(x,1,0);
            }
            else if(c[0] == 'Q')
            {
                sf(x);
                printf("%d\n",Query(1,x) );
            }
            else
            {
                if(x>0)
                {
                    x = s[--top];
                    updata_tree(x,1,1);
                }
            }
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值