hdu1540 Tunnel Warfare(线段树)(好题)

题目链接:点击链接

题意:

  • 有n个村庄,连成一条线,有三个操作。操作一,将指定的一个村庄摧毁;操作二,查询指定村庄所在的线段上有多少个没有被摧毁的连续的村庄(即连续区间的长度);操作三,将上次被摧毁的村庄重建。

思路:

  • 操作一和操作三是基础的单点更新。

  • 操作二的查询,需要查询连续区间的长度,建树的时候要对每个节点对应的区间[l, r]记录从l开始向右的最大连续区间,长度为prefix,从r开始向左的最大连续区间,长度为suffix,记录中间的最大连续区间,长度为medium。

  • push up操作。当前节点的medium值为左区间medium,右区间medium,左区间suffix和右区间prefix,三个值的最大者。prefix等于左区间prefix值,当左区间prefix值等于左区间长度时,说明左区间和右区间prefix相邻,当前prefix等于左区间prefix加右区间prefix。suffix同理。

  • 单点查询如何转换成区间查询?查询的时候,在整个区间缩小为一个点的过程中,判断目标点是否在当前区间的连续区间内,如果在,我们再查询该连续区间的端点。(相当于感染)这样就可以查找到目标点所在的连续区间。

代码

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

const int maxn = 60000;
stack<int> s; 

struct Node
{
    int medium;
    int prefix;
    int suffix;
}tree[maxn<<2];

void pushup(int rt, int len){
    int left_interval = (len - len/2);
    int right_interval = len / 2;

    if(tree[rt<<1].prefix==left_interval)
        tree[rt].prefix = tree[rt<<1].prefix+tree[rt<<1|1].prefix;
    else
        tree[rt].prefix = tree[rt<<1].prefix; 

    if(tree[rt<<1|1].suffix==right_interval)
        tree[rt].suffix = tree[rt<<1].suffix+tree[rt<<1|1].suffix;
    else                            
        tree[rt].suffix = tree[rt<<1|1].suffix;

    tree[rt].medium = max(tree[rt<<1].medium, tree[rt<<1|1].medium);
    tree[rt].medium = max(tree[rt<<1].suffix+tree[rt<<1|1].prefix, tree[rt].medium);
}

void build(int rt, int l, int r){
    if(l==r){
        tree[rt].prefix = tree[rt].suffix = tree[rt].medium = 1;
    }
    else{
        int mid = (l+r)>>1;
        build(rt<<1, l, mid);
        build(rt<<1|1, mid+1, r);
        pushup(rt, r-l+1);
    }
}

void update(int rt, int idx, int l, int r, int x){
    if(l==r && l==idx){
        tree[rt].medium = tree[rt].prefix = tree[rt].suffix = x;
    }
    else{
        int mid = (l+r)>>1;
        if(idx<=mid) update(rt<<1, idx, l, mid, x);
        if(idx>mid) update(rt<<1|1, idx, mid+1, r, x);
        pushup(rt, r-l+1);
    }
}

int query(int rt, int idx, int l, int r){
    if(l==r || tree[rt].medium==0 ||tree[rt].medium == (r-l+1)){
        return tree[rt].medium;
    }
    else{
        int mid = (l+r)>>1;
        if(idx<=mid){
            if(idx>=mid-tree[rt<<1].suffix+1)
                return query(rt<<1, idx, l, mid) + query(rt<<1|1, mid+1, mid+1, r);
            else
                return query(rt<<1, idx, l, mid);
        }
        if(midif(idx<=mid+1+tree[rt<<1|1].prefix-1)
                return query(rt<<1, mid, l, mid) + query(rt<<1|1, idx, mid+1, r);
            else
                return query(rt<<1|1, idx, mid+1, r);
        }
    }
}

int main(){
    int n, q, x;
    char opt[10];
    while(scanf("%d%d", &n, &q)!=EOF){
        while(!s.empty()) s.pop();
        build(1, 1, n);

        for(int i=0; iscanf("%s", opt);
            if(opt[0]=='D'){
                scanf("%d", &x);
                update(1, x, 1, n, 0);
                s.push(x);
            }
            if(opt[0]=='Q'){
                scanf("%d", &x);
                printf("%d\n", query(1, x, 1, n));
            }
            if(opt[0]=='R'){
                if(!s.empty()){
                    update(1, s.top(), 1, n, 1);
                    s.pop();
                }
            }
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构)