POJ 2892 Tunnel Warfare && HDOJ 1540 (线段树)

POJ   http://poj.org/problem?id=2892 单case

HDOJ http://acm.hdu.edu.cn/showproblem.php?pid=1540 多cases


建立线段树,区间划分为[l, mid), [mid, r), 并记录区间从左右端点开始最大连续长度,初始时,即为整个区间长度,维护这样的结构可以查询与每个村庄相连的最多村庄。


线段树的每个区间维护:

从左端点开始的连续最大值 lval

从右端点开始的连续最大值 rval

区间的状态;0: 区间代表的所有村庄都毁掉

                      1: 所有村庄都完好

                      -1:有些毁坏,有些没有


村庄1,2,3,4,5,6,7可以用区间[1, 8)代表

毁坏村庄x的时候,可以看作对叶子区间[x, x+1)修改,修改维护的变量并向上一直更新父亲节点维护的变量

修复村庄同理

查询的时候,需要定位村庄所在区间,若区间内村庄都被毁或者都完好,则直接可以得到结果(0或者区间长)

处于混合状态,有时需要将左右孩子结果合并,否则继续递归查询。


合并的两种情况:

1:  mid - l <= 左孩子从右端点起的最大连续长度

    则结果为: 左孩子从右端点起的最大连续长度+右孩子从左端点起的最大连续长度

2: l-mid +1 <= 右孩子从左端点起的最大连续长度

    则结果为: 左孩子从右端点起的最大连续长度+右孩子从左端点起的最大连续长度

l表示村庄,mid为线段树区间中点

注:代码里记录区间最大值的max其实没用--|||

/*===============================================================
*   Copyright (C) 2012 All rights reserved.
*   
*   file: 2892_Tunnel_Warfare.cpp
*   author: ivapple
*   date: 2012-09-07
*   description: 
*
*   update log: 
*
================================================================*/
#include <cstdlib>
#include <cstdio>

#include <iostream>
#include <stack>
#include <string>
#include <cstring>
#define out(x) (cout<<#x<<": "<<x<<endl)

#define FOR(i,s,t) for(i=s; i<t; i++)

using namespace std;

template<class T>void show(T a, int n){int i; for(i=0;i<n;i++)cout<<a[i]<<" ";cout<<endl;}

template<class T>void show(T a, int r, int l){int i; for(i=0;i<r;i++)show(a[i],l);cout<<endl;}

const int kMaxVillage = 50001;

struct SegTree
{
    int s, e; //[s,e)
    int lc, rc; //left child, right child
    int flag; //0 destroy, 1 not, -1 combine
    int lval, rval, max;
}tree[4*kMaxVillage];
int id = -1;

void BuildTree(int l, int r)
{
    int mid;
    int root = ++id;
    tree[root].s = l;
    tree[root].e = r;
    //cout << root << " " << l << " " << r << " " << endl;
    //cout << tree[root].s << " " << tree[root].e << endl;
    tree[root].flag = 1; //not destroy
    tree[root].lval = tree[root].rval = tree[root].max = r-l; //length of region
    if (l<r-1)
    {
        mid = (l+r)/2;
        tree[root].lc = id+1;
        BuildTree(l, mid);
        tree[root].rc = id+1;
        BuildTree(mid, r);
    }
}

int Max(int a, int b, int c)
{
    int max;
    max = a>b?a:b;
    max = max>c?max:c;
}

void Update(int root)
{
    // update flag
    int lc = tree[root].lc;
    int rc = tree[root].rc;
    if (tree[lc].flag == 1 && tree[rc].flag == 1) // all ok
        tree[root].flag = 1;
    else
        if (tree[lc].flag == 0 && tree[rc].flag == 0) // all destroy
            tree[root].flag = 0;
        else
            tree[root].flag = -1; //combine
    // update value
    tree[root].lval = tree[lc].lval + (tree[lc].flag == 1? tree[rc].lval:0);
    tree[root].rval = tree[rc].rval + (tree[rc].flag == 1? tree[lc].rval:0);
    //tree[root].max = Max(tree[lc].rval+tree[rc].lval, tree[root].lval, tree[root].rval);
}
//l is viilage number
//opt 1 repair  
//opt 0 destory
void ModifyTree(int root, int l, int r, int opt)
{
    //cout << l << " " << r << " " << root <<endl;
    //out(tree[root].s);
    //out(tree[root].e);
    //leaf
    if (l==tree[root].s && tree[root].e==r)
    {
        tree[root].flag = opt; //0 destroy 1 ok -1 combine
        tree[root].lval = opt;
        tree[root].rval = opt;
        tree[root].max = opt;
        return;
    }
    int mid = (tree[root].s+tree[root].e)/2;
    if (l < mid)
        ModifyTree(tree[root].lc, l, r, opt);
    if (r > mid)
        ModifyTree(tree[root].rc, l, r, opt);
    Update(root);
}

int Query(int root, int l, int r)
{
    int lc = tree[root].lc;
    int rc = tree[root].rc;
    //cout << root << " " << l << " " << r << endl;
    if (tree[root].flag ==1) //all ok
        return tree[root].e-tree[root].s;
    if (tree[root].flag == 0) //all destory
        return 0;
    //if (tree[root].e-1 == tree[root].s)
    //    return 0;
    int mid = (tree[root].s+tree[root].e)/2;
    if (l < mid)
    {
        if (mid-l <= tree[lc].rval)
            return tree[lc].rval + tree[rc].lval;
        return Query(lc, l, r);
    }
    if (r > mid)
    {
    //cout << l <<" " <<  mid << " " <<rc << " " <<tree[rc].lval << endl;
        if (l-mid+1 <= tree[rc].lval)
            return tree[rc].lval + tree[lc].rval;
        return Query(rc, l, r);
    }
}

int main()
{
    int n, m;
    char cmd, buf;
    int village;
    int ans;
    stack<int> st;
#ifndef ONLINE_JUDGE
    freopen("test.txt", "r", stdin);
#endif
    while (scanf("%d%d", &n, &m)!=EOF)
    {
        id = -1;
        memset(tree,0,4*kMaxVillage);
        BuildTree(1, n+1);
        while (m--)
        {
            scanf("%c", &buf);
            scanf("%c", &cmd);
    //    out(buf);
    //    out(cmd);
            if (cmd == 'D')
            {
                scanf("%d", &village);
            //out(village);
                st.push(village);
                ModifyTree(0, village, village+1, 0);
            }
            if (cmd == 'Q')
            {
                scanf("%d", &village);
                //out(village);
                ans = Query(0, village, village+1);
                printf("%d\n", ans);
            }
            if (cmd == 'R')
            {
                village = st.top();
                st.pop();
                ModifyTree(0, village, village+1, 1);
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值