HDU 1540-Tunnel Warfare(线段树+区间合并)

Tunnel Warfare

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


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 9D 3D 6D 5Q 4Q 5RQ 4RQ 4
 
Sample Output
 
      
1024
 

Source
 

题目大意:给你n个城市,一开始都是相互连通的,然后有m次操作,D:破坏城市x,R修复城市x,Q:查询x与相邻多少城市连通。

解题思路:这是一道线段树区间合并与单点查询的题目,主要是查询的过程,个人感觉区间合并的题目比较高深,想要理解还是需要你仔细思考一下的!解释就在代码中了,自己体会吧。

如果还没理解线段树的区间区间合并的话戳这里:线段树的区间合并详解

AC代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include<stdlib.h>
#include<queue>
#include<map>
#include<set>
#define bug printf("*********\n");
#define mem0(a) memset(a, 0, sizeof(a));
#define mem1(a) memset(a, -1, sizeof(a));
#define in1(a) scanf("%d" ,&a);
#define in2(a, b) scanf("%d%d", &a, &b);
#define out1(a) printf("%d\n", a);
#define out2(a, b) printf("%d %d\n", a, b);
using namespace std;
typedef long long LL;
typedef pair<int, int> par;
const LL mod = 2000000000000000003;
const int INF = 1e9+7;
const int N = 1000010;
const double pi = 3.1415926;

int n, m, cnt;
char str[2];

struct node
{
    int l;
    int r;
    int lnum; //区间最长连续左区间长度(最左端开始)
    int rnum; //区间最长连续右区间长度(同理)
    int mnum; //区间最长连续区间长度
}e[50010*4];

void build(int l, int r, int k)
{
    e[k].l = l;
    e[k].r = r;
    e[k].lnum = e[k].rnum = e[k].mnum = r-l+1; //初始化长度
    if(l == r) return;
    int mid = (l+r)/2;
    build(l ,mid, 2*k);
    build(mid+1, r, 2*k+1);
}

void updata(int i, int k, int add)
{
    if(e[k].l == e[k].r) {
        e[k].lnum = e[k].rnum = e[k].mnum = add;
        return;
    }
    int mid = (e[k].l+e[k].r)/2;
    if(i <= mid) {
        updata(i, 2*k, add);
    }else updata(i, 2*k+1, add);
    e[k].lnum = e[2*k].lnum;
    e[k].rnum = e[2*k+1].rnum;
    e[k].mnum = max(max(e[2*k].mnum, e[2*k+1].mnum), e[2*k].rnum+e[2*k+1].lnum);
    //父区间最大长度等于左右儿子区间最大长度或者最儿子右区间长度加右儿子左区间长度的最大值
    if(e[2*k].lnum == e[2*k].r-e[2*k].l+1) //如果左儿子左区间全连续,父亲左区间长度则要加上右儿子左区间长度
        e[k].lnum += e[2*k+1].lnum;
    if(e[2*k+1].rnum == e[2*k+1].r-e[2*k+1].l+1) //右区间同理
        e[k].rnum += e[2*k].rnum;
}

int quary(int i, int k) //这是单点查询连续(重点理解)
{
    if(e[k].l == e[k].r || e[k].mnum == 0 || e[k].mnum == e[k].r - e[k].l + 1) {
        return e[k].mnum;
    }
    int mid = (e[k].l+e[k].r)/2;
    if(i <= mid) { //位于左边的区间
        if(i >= e[2*k].r - e[2*k].rnum + 1) { //如果查询的点从该点起一直连续到左区间最右端,则要继续加上该点右边的连续值
            return quary(i, 2*k) + quary(mid+1, 2*k+1);
        }else return quary(i, 2*k);
    }else {
        if(i <= e[2*k+1].l+e[2*k+1].lnum - 1) { //对于位于又右边的同理
            return quary(mid, 2*k) + quary(i, 2*k+1);
        }else return quary(i, 2*k+1);
    }
}

int main()
{
    int x, a[50010];
    while(~scanf("%d%d", &n, &m)) {
        cnt = 1;
        int idx = 0;
        build(1, n, 1);;
        while(m --) {
            scanf("%s", str);
            if(str[0] == 'D') {
                scanf("%d", &a[idx]);
                updata(a[idx], 1, 0);
                idx++;
            }else if(str[0] == 'Q'){
                scanf("%d", &x);
                printf("%d\n", quary(x, 1));
            }else {
                idx --;
                updata(a[idx], 1, 1);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/i_believe_cwj/article/details/80434195