hdu 1540 Tunnel Warfare (线段树维护左右最长连续区间)

题意是一条线上的点,D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点。
线段树结点 设置一个 ll 记录区间左端点开始的最大连续个数, rl 记录区间右端点开始的最大的连续个数,
ml表示该区间最大的连续点的个数。

主要是更新和查询两个操作。

/*
key: ll,rl,ml;//左起最大长度,右起最大长度,区间最大长度

求与某点相连的连续最长距离。
线段树优化了求连续最长的时间,枚举是O(n),线段树O(log2[n])
*/

#include <cstdio>
#include <stack>
using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define N 50005

int max3(int x, int y, int z)
{
    x = x > y ? x : y;
    return z > x ? z : x;
}

struct Seq
{
    int ll,rl,ml;//左起最大长度,右起最大长度,区间最大长度
}seq[N<<2];

stack<int> st;

void build(int l, int r, int rt)
{
    if(l==r)
        seq[rt].ml = seq[rt].ll = seq[rt].rl = 1;
    else
    {
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        seq[rt].ml = seq[rt].ll = seq[rt].rl = seq[rt<<1].ml + seq[rt<<1|1].ml;
    }
}

void update(int i, int add, int l, int r, int rt)
{
    if(l==r)
    {
        seq[rt].ml = add;
        seq[rt].ll = seq[rt].rl = seq[rt].ml;
    }
    else
    {
        int m = (l + r) >> 1;
        if(i<=m)
            update(i, add, lson);
        else
            update(i, add, rson);
        seq[rt].ll = seq[rt<<1].ll;
        if(m-l+1== seq[rt<<1].ml)//左孩子区间最大长度等于区间长度
            seq[rt].ll += seq[rt<<1|1].ll;
        seq[rt].rl = seq[rt<<1|1].rl;
        if(r - m == seq[rt<<1|1].ml)//右孩子区间最大长度等于区间长度
            seq[rt].rl += seq[rt<<1].rl;
        //父亲节点区间最大长度 为 max(左孩子右起最大长度+右孩子左起最大长度 ,左孩子区间最大长度,右孩子区间最大长度)
        seq[rt].ml = max3(seq[rt<<1].ml, seq[rt<<1|1].ml, seq[rt<<1].rl+seq[rt<<1|1].ll);
    }
}

int query(int pos, int l, int r, int rt)
{
    if(l==r || seq[rt].ml==0 || seq[rt].ml == r - l + 1)//叶子节点 或 区间最大长度等0 或 区间最大长度等于整个区间长度
        return seq[rt].ml;
    else
    {
        int m = (l + r) >> 1;
        int ret = 0;
        if(pos<=m)//查找点在左子树
        {
            ret = query(pos, l, m, rt<<1);
            if(pos > m - seq[rt<<1].rl)//查找点在右起第一断点的右边
                ret += seq[rt<<1|1].ll;
        }
        else//在右子树
        {
            ret = query(pos, m+1, r, rt<<1|1);
            if(pos < m + 1 + seq[rt<<1|1].ll)//查找点在左起第一断点的左边
                ret += seq[rt<<1].rl;
        }
        return ret;
    }
}

int main()
{
    int n, m, x;
    char s[5];
    while(scanf("%d%d", &n, &m)!=EOF)
    {
    build(1, n, 1);
    while(!st.empty()) st.pop();
    for(int i=1; i<=m; i++)
    {
        scanf("%s",s);
        if(s[0]=='D')
        {
            scanf("%d",&x);
            update(x, 01, n, 1);
            st.push(x);
        }
        else if(s[0]=='R')
        {
            x = st.top();
            st.pop();
            update(x, 11, n, 1);
        }
        else if(s[0]=='Q')
        {
            scanf("%d",&x);
            printf("%d\n",query(x, 1, n, 1));
        }
    }
    }
    return 0;
}
View Code 

 

 

posted @ 2013-11-11 20:56  byluoluo  阅读(240)  评论(0编辑  收藏  举报