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;
}


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