Tunnel Warfare

Tunnel Warfare

Time Limit:2000MS    Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

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 connected with two neighboring ones.

Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!
 

Input

The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event.

There are three different events described in different format shown below:

D x: The x-th village was destroyed.

Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.

R: The village destroyed last was rebuilt.
 

Output

Output the answer to each of the Army commanders’ request in order on a separate line.
 

Sample Input

7 9 D 3 D 6 D 5 Q 4 Q 5 R Q 4 R Q 4
 

Sample Output

1 0 2 4
 
题意:n座村庄,除了第一座和最后一座,其他的相邻之间的村庄都是双联通,m条指令,指令一共有三种:①D x 摧毁第x座村庄;②R  上一个被摧毁的村庄已经重建;③Q x  询问与第x座村庄直接、间接相连(包括自身)的村庄有多少。
思路:线段树区间合并。用1表示村庄被摧毁,0表示村庄已经重建。所求问题可以转化成为:①所询问的村庄x是被摧毁的,那么x = 1,与它相连的村庄个数为0,即包括x在内,连续的0的个数为0;②x = 0,则与x左右连续的0的个数便为相通的村庄数目。
父亲结点左区间 = 左子树左区间,父亲结点右区间 = 右子树右区间
代码:

#include"stack"
#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"

using namespace std;

#define MAXN 500005
#define lson id << 1
#define rson id << 1 | 1

int n,m;

struct TREE
{
    int l,r;
    int lc,rc,mc;
}tree[MAXN << 2];

stack < int > ST ;

void build(int id,int l,int r)
{
    tree[id].l = l;
    tree[id].r = r;
    tree[id].lc = tree[id].rc = tree[id].mc = r - l + 1;
    if(l != r)
    {
        int mid = (l + r) >> 1;
        build(lson,l,mid);
        build(rson,mid+1,r);
    }
}

void update(int id,int pos,int op)
{
    if(tree[id].l == tree[id].r)
    {
        if(op) //毁坏
        {
            tree[id].mc = tree[id].lc = tree[id].rc = 0;
        }
        else   //重建
        {
            tree[id].mc = tree[id].lc = tree[id].rc = 1;
        }
    }
    else
    {
        int mid = (tree[id].r + tree[id].l) >> 1;
        if(pos <= mid)
        {
            update(lson,pos,op);
        }
        else
        {
            update(rson,pos,op);
        }
        tree[id].lc = tree[lson].lc; //左区间
        tree[id].rc = tree[rson].rc; //右区间
        tree[id].mc = max((tree[lson].rc + tree[rson].lc),max(tree[lson].mc,tree[rson].mc));
        //父结点的最大连续区间为左子树的最大、右子树最大、左右子树合并区间中的一个
        if(tree[lson].mc == tree[lson].r - tree[lson].l + 1) //左子树区间满
        {
            tree[id].lc += tree[rson].lc;                    //父亲左区间加上右子树的左区间
        }
        if(tree[rson].mc == tree[rson].r - tree[rson].l + 1) //右子树区间满
        {
            tree[id].rc += tree[lson].rc;                    //父亲右区间加上左子树的右区间
        }
    }
}

int query(int id,int num)
{
    if(tree[id].l == tree[id].r || tree[id].mc == 0 || tree[id].mc == tree[id].r - tree[id].l + 1)
    //如果为叶子结点或者区间为空(满),则不用继续查询
    {
        return tree[id].mc;
    }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(num <= mid) //查左子树
    {
        if(num >= tree[lson].r - tree[lson].rc + 1) //num>=左子树右边连续区间的右边界值
        {
            return query(lson,num) + query(rson,mid+1); //与右子树左区间有联系
        }
        else
        {
            return query(lson,num);
        }
    }
    else           //查右子树
    {
        if(num <= tree[rson].l + tree[rson].lc - 1) //num<=右子树左边连续区间的右边界值
        {
            return query(rson,num) + query(lson,mid);  //与左子树右区间有关系
        }
        else
        {
            return query(rson,num);
        }
    }
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        while(! ST.empty())
        {
            ST.pop();
        }
        build(1,1,n);
        while(m--)
        {
            char str[5];
            int num;
            scanf("%s",str);
            if(str[0] == 'D') //1表示毁坏
            {
                scanf("%d",&num);
                ST.push(num);
                update(1,num,1);
            }
            else if(str[0] == 'R' && !ST.empty()) //0表示重建,考虑了一下没有毁坏但是却出现重建指令的可能
            {
                int temp = ST.top();
                ST.pop();
                update(1,temp,0);
            }
            else
            {
                scanf("%d",&num);
                printf("%d\n",query(1,num));
            }
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章