HDU-1540 Tunnel Warfare(线段树)

Tunnel Warfare

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 12058    Accepted Submission(s): 4709

 

Problem 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个村子被摧毁

Q x:输出 包含第x个村子在内的 最长未被摧毁的村子数量

R:将上一个被摧毁的村子修复

思路:

线段树模板题。需要注意的是题目给出的是单样例,但实际上是多样例。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;

#define ls root*2
#define rs root*2+1 
#define lson ls,l,m
#define rson rs,m+1,r
const int maxn=50005;

struct Node{
    int l,r;
	int max_sub; //区间最长连续子串和 
	int max_pre; //区间最长前缀和 
	int max_suf; //区间最长后缀和 
}tree[maxn<<2];

int ok[maxn]; // ok[i]=1 表示第i个村子是完好的,值为0时表示第i个村子被摧毁了 

void build(int root,int l,int r) // 建树 
{
    tree[root].l=l;tree[root].r=r;
    tree[root].max_sub=tree[root].max_pre=tree[root].max_suf=r-l+1;
    if(l == r)
        return;
    int m=(l+r)/2;
    build(lson);
    build(rson);
}
void change(int root)
{
    if(tree[ls].max_pre == (tree[ls].r-tree[ls].l+1)) // 左儿子整个区间都是完好的 
    {
        if(tree[rs].max_suf == (tree[rs].r-tree[rs].l+1)) // 右儿子整个区间都是完好的 
        {
            tree[root].max_pre=tree[root].max_suf=tree[root].max_sub=tree[root].r-tree[root].l+1;
        }
        else
        {
        	//// 由于右儿子存在被摧毁的村子,所以 根节点的最长连续子串和 = 根节点最长前缀和 = 整个左儿子区间 + 右儿子前缀和 
            tree[root].max_sub=tree[root].max_pre=tree[ls].max_pre+tree[rs].max_pre;
            // 根节点的最长后缀 = 右儿子的最长后缀和
            tree[root].max_suf=tree[rs].max_suf;
        }
    }
    else 		// 左儿子区间存在被摧毁的村子 
    {
        if(tree[rs].max_suf == (tree[rs].r-tree[rs].l+1)) // 右儿子整个区间都是完好的
        {
            tree[root].max_sub=tree[root].max_suf=tree[rs].max_suf+tree[ls].max_suf;
            tree[root].max_pre=tree[ls].max_pre;
        }
        else
        {
            tree[root].max_pre=tree[ls].max_pre;
            tree[root].max_suf=tree[rs].max_suf;
            tree[root].max_sub=max(tree[ls].max_sub,tree[rs].max_sub);
            tree[root].max_sub=max(tree[root].max_sub,tree[ls].max_suf+tree[rs].max_pre);
        }
    }
}
void destroy(int root,int l,int r,int a)
{
    if(l==r) //叶节点 
    {
        if(l==a) // 被摧毁的村子的叶节点 
            tree[root].max_pre=tree[root].max_sub=tree[root].max_suf=0;
        return ;
    }
    int m=(l+r)/2;
    if(a<=m) 
        destroy(lson,a);
    else
        destroy(rson,a);
    change(root);
}
void rebuild(int root,int l,int r,int a) //同 destroy函数,只是 被摧毁的村子的叶节点的值改为 1 
{
    if(l==r)
    {
        if(l==a)
            tree[root].max_pre=tree[root].max_sub=tree[root].max_suf=1;
        return ;
    }
    int m=(l+r)/2;
    if(a<=m)
        rebuild(lson,a);
    else
        rebuild(rson,a);
    change(root);    
}

int query(int root, int l, int r, int a)  
{
    if( l==r || tree[root].max_sub==(r-l+1) || !tree[root].max_sub) //如果本身是叶节点 或 整个区间都是完好的 或 整个区间都被摧毁的情况下 
        return tree[root].max_sub;
    int m=(l+r)/2;
    if(a<=m) //a村在目前根节点的左儿子区间 
    {
        if( a >= m-tree[ls].max_suf+1) // 横跨左右儿子区间 
            return tree[ls].max_suf+tree[rs].max_pre; //左儿子后缀和加右儿子前缀和 
            
        else
            return query(lson,a);
    }
    else  //a村在目前根节点的右儿子区间
    {
        if( a <= m + tree[rs].max_pre + 1)
            return tree[ls].max_suf + tree[rs].max_pre;
        else 
            return query(rson,a);
    }
}
int main(void)
{
    int n,m,a;
    
    char c;
    
    while(~scanf("%d %d",&n,&m))
    {
    getchar();memset(ok,1,sizeof(ok));stack<int> q;
    build(1,1,n);
    while(m--)
    {
        scanf("%c",&c);getchar();
        switch(c){
            case 'D':{
                scanf("%d",&a);getchar();
                q.push(a);ok[a]=0;
                destroy(1,1,n,a);
                break;
            }
            case 'R':{
                if(!q.empty())
                {
                    rebuild(1,1,n,q.top());
                    ok[q.top()]=1;
                    q.pop();
                }
                break;
            }
            case 'Q':{
                scanf("%d",&a);getchar();
                
                if(ok[a]==0)printf("0\n");
                else
                {
                    printf("%d\n",query(1,1,n,a));
                }
                break;
            }
        }
    }
}
}

猜你喜欢

转载自blog.csdn.net/theendbigins/article/details/81182578