1. 程式人生 > >HDU1540 Tunnel Warfare 線段樹區間合併

HDU1540 Tunnel Warfare 線段樹區間合併

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                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
   
  
  


 

 

題意:D代表破壞村莊,R代表修復最後被破壞的那個村莊,Q代表詢問包括x在內的最大連續區間是多少

思路:程式碼中的註釋已經比較詳細了,所以不多解釋什麼,線上段樹的區間內,我們要用三個變數記錄左邊連續區間,右邊連續區間和最大連續區間

 

#include <stdio.h>#include <string.h>
#include <algorithm>#include <math.h>#include <stdlib.h>using namespace std;const int maxn = 50000+10;int n,m;int s[maxn],top;//s為模擬棧struct node{    int l,r;    int ls,rs,ms;//ls,左端最大連續區間,rs右端最大連續區間,ms區間內最大連續區間} a[maxn<<2];void init(int l,int r,int i){    a[i].l = l;    a[i].r = r;    a[i].ls = a[i].rs = a[i].ms = r-l+1
;    if(l!=r)    {        int mid = (l+r)>>1;        init(l,mid,i*2);        init(mid+1,r,2*i+1);    }}void insert(int i,int t,int x){    if(a[i].l == a[i].r)    {        if(x==1)            a[i].ls = a[i].rs = a[i].ms = 1;//修復        else            a[i].ls = a[i].rs = a[i].ms = 0;//破壞        return ;    }    int mid = (a[i].l+a[i].r)>>1;    if(t<=mid)        insert(2*i,t,x);    else        insert(2*i+1,t,x);    a[i].ls = a[2*i].ls;//左區間    a[i].rs = a[2*i+1].rs;//右區間    a[i].ms = max(max(a[2*i].ms,a[2*i+1].ms),a[2*i].rs+a[2*i+1].ls);//父親區間內的最大區間必定是,左子樹最大區間,右子樹最大區間,左右子樹合併的中間區間,三者中最大的區間值    if(a[2*i].ls == a[2*i].r-a[2*i].l+1)//左子樹區間滿了的話,父親左區間要加上右孩子的左區間        a[i].ls += a[2*i+1].ls;    if(a[2*i+1].rs == a[2*i+1].r-a[2*i+1].l+1)//同理        a[i].rs += a[2*i].rs;}int query(int i,int t){    if(a[i].l == a[i].r || a[i].ms == 0 || a[i].ms == a[i].r-a[i].l+1)//到了葉子節點或者該訪問區間為空或者已滿都不必要往下走了        return a[i].ms;    int mid = (a[i].l+a[i].r)>>1;    if(t<=mid)    {        if(t>=a[2*i].r-a[2*i].rs+1)//因為t<=mid,看左子樹,a[2*i].r-a[2*i].rs+1代表左子樹右邊連續區間的左邊界值,如果t在左子樹的右區間內,則要看右子樹的左區間有多長並返回            return query(2*i,t)+query(2*i+1,mid+1);        else            return query(2*i,t);//如果不在左子樹的右邊界區間內,則只需要看左子樹    }    else    {        if(t<=a[2*i+1].l+a[2*i+1].ls-1)//同理            return query(2*i+1,t)+query(2*i,mid);        else            return query(2*i+1,t);    }}int main(){    int i,j,x;    char ch[2];    while(~scanf("%d%d",&n,&m))    {        top = 0;        init(1,n,1);        while(m--)        {            scanf("%s",ch);            if(ch[0] == 'D')            {                scanf("%d",&x);                s[top++] = x;                insert(1,x,0);            }            else if(ch[0] == 'Q')            {                scanf("%d",&x);                printf("%d\n",query(1,x));            }            else            {                if(x>0)                {                    x = s[--top];                    insert(1,x,1);                }            }        }    }    return 0;}


 

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述