1. 程式人生 > >hdu 1540/POJ 2892 Tunnel Warfare 【線段樹區間合並】

hdu 1540/POJ 2892 Tunnel Warfare 【線段樹區間合並】

article 遞歸 線段 tdi != lines nor sample eight

Tunnel Warfare

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
鏈接:hdu 1540 POJ 2892

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個點。點的編號是從1 ~ N,M次‘Q’或‘D或‘R’的操作,“D x”表示的是破壞這個點x,“R”是修復之前破壞的點,“Q x”表示詢問點x所在連續區間的長度。假定最初每一個點都是好的。

分析:

首先對操作進行分析:能夠把D操作看成把區間在點x出截斷,R操作是把x左右【包含點x】進行合並。

每次合並兩個區間 [a,b] , [c,d] 的時候,得到的新的區間[a,d] 的最大連續區間長度為:

Len(a,d) = max{ Len(a,b),Len(c,d) ,End(b) + Begin(c) }; <==

有一點分治的思想

End(b)表示以b結尾的最大連續區間長度。Begin(c)表示以c開頭的最大連續區間長度,這裏我們能夠知道,合並兩個區間,並非簡單的區間加減。而是還要保持一個以區間第一個元素開始的最大連續區間長度以及 以區間最後一個元素結尾的最大連續區間長度。

那麽。如今問題就比較好辦了。線段樹每一個節點包括三個信息。各自是以區間第一個元素開始的最大連續區間長度ln。以區間最後一個元素結尾的最大連續區間長度rn以及區間最大連續長度mn

接下來,便是Q操作了,詢問點x 所在連續區間的長度。

在遞歸左兒子節點的時候,註意一下,x是否在以左兒子區間最後一個元素結尾長度為左兒子rn的範圍裏面,假設在,那麽x所在的連續區間便有可能包括右兒子的一部分,遞歸右兒子的時候,同理!

/****************************>>>>HEADFILES<<<<****************************/
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
/****************************>>>>>DEFINE<<<<<*****************************/
#define fst             first
#define snd             second
#define root            1,N,1
#define lson            l,mid,rt<<1
#define rson            mid+1,r,rt<<1|1
#define PB(a)           push_back(a)
#define MP(a,b)         make_pair(a,b)
#define CASE(T)         for(scanf("%d",&T);T--;)
#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef __int64         LL;
const int INF = 0x3f3f3f3f;
/****************************>>>>SEPARATOR<<<<****************************/
const int maxn = 50000 + 5;
int N, M;
struct Node
{
    int ln, rn, mn;
} segtree[maxn << 4];
inline void PushUp(const int& rt, const int& l, const int& r)
{
    segtree[rt].ln = segtree[rt << 1].ln;
    segtree[rt].rn = segtree[rt << 1 | 1].rn;
    segtree[rt].mn = max(segtree[rt << 1].rn + segtree[rt << 1 | 1].ln, 
                         max(segtree[rt << 1].mn, segtree[rt << 1 | 1].mn));
    int mid = (l + r) >> 1;
    if(segtree[rt << 1].mn == mid - l + 1) segtree[rt].ln += segtree[rt << 1 | 1].ln;
    if(segtree[rt << 1 | 1].mn == r - (mid + 1) + 1) segtree[rt].rn += segtree[rt << 1].rn;
}
void Build(int l, int r, int rt)
{
    segtree[rt].ln = segtree[rt].rn = segtree[rt].mn = r - l + 1;
    if(l == r)
    {
        return ;
    }
    int mid = (l + r) >> 1;
    Build(lson);
    Build(rson);
}
void Update(int pos, int val, int l, int r, int rt)
{
    if(l == r)
    {
        segtree[rt].ln = segtree[rt].rn = segtree[rt].mn = val;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid)
        Update(pos, val, lson);
    else
        Update(pos, val, rson);
    PushUp(rt, l, r);
}
int Query(int pos, int l, int r, int rt)
{
    if(r - l + 1 == segtree[rt].mn || r  == l || segtree[rt].mn == 0)
    {
        return segtree[rt].mn;
    }
    int mid = (l + r) >> 1, ret = 0;
    if(pos <= mid)
    {
        if(pos >= mid - segtree[rt << 1].rn + 1)
            ret = Query(pos, lson) + Query(mid + 1, mid + 1, r, rt << 1 | 1);
        else ret = Query(pos, lson);
    }
    else
    {
        if(pos <= (mid + 1) + segtree[rt << 1 | 1].ln - 1)
            ret = Query(pos, rson) + Query(mid, l, mid, rt << 1);
        else ret = Query(pos, rson);
    }
    return ret;
}
int destroy[maxn];
int main()
{
    //FIN;
    while(~scanf("%d %d", &N, &M))
    {
        Build(root);
        char Op[5];
        int x, cnt = 0;
        for(int i = 0; i < M; i++)
        {
            scanf("%s", Op);
            if(Op[0] == 'Q')
            {
                scanf("%d", &x);
                printf("%d\n", Query(x, root));
            }
            else if(Op[0] == 'D')
            {
                scanf("%d", &x);
                Update(x, 0, root);
                destroy[cnt++] = x;
            }
            else
            {
                x = destroy[--cnt];
                Update(x, 1, root);
            }
        }
    }
}

一年之後,再寫了一遍這個題目。感覺代碼風格還是變化了一點。再貼個代碼~

#include <bits/stdc++.h>

using namespace std;

const int MX = 5e4 + 5;

#define lch     (rt << 1)
#define rch     (rt << 1 | 1)

typedef pair<int, int> PII;

struct Seg {
    /**
      * status:
      * 0 -- Bad
      * 1 -- Good
      * -1 -- not cover
      * I: 節點相應區間兩端點以及兩短點的標號
      */
    int sum, status;
    PII I[2];
} seg[MX * 3];

int N, M, x;
char oper[5];

inline void pushUp(int rt) {
    if(seg[lch].status == seg[rch].status) seg[rt].status = seg[lch].status;
    else seg[rt].status = -1;

    if(seg[lch].status == 1 && seg[rch].status == 1) seg[rt].sum = seg[lch].sum + seg[rch].sum;
    else seg[rt].sum = 0;
}

void build(int l, int r, int rt) {
    int temp;
    if(l == r) {
        seg[rt].sum = seg[rt].status = 1;
        seg[rt].I[0] = make_pair(l, rt);
        seg[rt].I[1] = make_pair(r, rt);
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, lch);
    build(mid + 1, r, rch);
    pushUp(rt);
    seg[rt].I[0] = seg[lch].I[0];
    seg[rt].I[1] = seg[rch].I[1];
}

void update(int pos, int v, int l, int r, int rt) {
    if(l == r) {
        seg[rt].status = v;
        seg[rt].sum = (v == 1) ? 1 : 0;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) update(pos, v, l, mid, lch);
    else update(pos, v, mid + 1, r, rch);
    pushUp(rt);
}

int query_status(int pos, int l, int r, int rt) {
    if(l == r) return seg[rt].status;
    int mid = (l + r) >> 1;
    if(pos <= mid) return query_status(pos, l, mid, lch);
    else return query_status(pos, mid + 1, r, rch);
}

int query(int pos, int l, int r, int rt, int d) {
    if(seg[rt].status == 0) return 0;
    int mid = (l + r) >> 1, ret = 0;
    if(seg[rt].status == 1) {
        ret += seg[rt].sum;
        PII &lb = seg[rt].I[0], &ub = seg[rt].I[1];
        if(lb.first != 1 && seg[lb.second].status == 1 && d != 1)
            ret += query(lb.first - 1, 1, N, 1, -1);
        if(ub.first != N && seg[ub.second].status == 1 && d != -1)
            ret += query(ub.first + 1, 1, N, 1, 1);
        return ret;
    }
    if(pos <= mid) {
        ret += query(pos, l, mid, lch, d);
    } else {
        ret += query(pos, mid + 1, r, rch, d);
    }
    return ret;
}

int main() {
//    freopen("input.txt", "r", stdin);
    while(~scanf("%d %d", &N, &M)) {
        build(1, N, 1);
        stack<int> buf;
        while(M --) {
            scanf("%s", oper);
            if(oper[0] == 'D') {
                scanf("%d", &x); buf.push(x);
                update(x, 0, 1, N, 1);
            } else if(oper[0] == 'Q') {
                scanf("%d", &x);
                int k = query_status(x, 1, N, 1), ans = 0;
                if(k != 0) {
                    ans = query(x, 1, N, 1, 0);
                }
                printf("%d\n", ans);
            } else {
                if(buf.empty()) continue;
                x = buf.top(); buf.pop();
                update(x, 1, 1, N, 1);
            }
        }
    }
    return 0;
}


hdu 1540/POJ 2892 Tunnel Warfare 【線段樹區間合並】