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

HDU1540 Tunnel Warfare(線段樹區間合併)

HDU1540  Tunnel Warfare(線段樹區間合併)

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個村莊排成一列,一開始村莊都與相鄰村莊通過地下通道相連,D代表 把這個村莊與相鄰的村莊隔斷,R代表修復上一個被隔斷的村莊,即與相鄰村莊重新相連,Q代表查詢這個村莊能與多少個村莊相連,包括自己

思路:線段樹區間合併題,ls表示從左邊界開始的最長連續區間,rs表示從右邊界開始的最長連續區間,maxs代表該區間內的最長連續區間,建樹的時候ls,rs,maxs初始化為r-l+1,更新時為單點更新,pushdown時,先讓 ls為左子樹的ls,rs為右子樹的rs,然後如果左子樹的ls等於左子樹的區間長,則父節點的ls能與右子樹的ls相連,rs同理,maxs則為左子樹的maxs 右子樹的maxs 左子樹rs加右子樹ls的最大值,查詢時,看程式碼註釋

#include<stdio.h>
#include<algorithm>
using namespace std;
const int MAXN=50005;
struct NODE{
	int l,r;
	int ls,rs,maxs;
}segTree[MAXN<<2];
void build(int num,int l,int r)
{
	segTree[num].l=l;
	segTree[num].r=r;
	segTree[num].ls=segTree[num].rs=segTree[num].maxs=r-l+1;
	if(l==r)  return;
	int mid=(l+r)>>1;
	build(num<<1,l,mid);
	build(num<<1|1,mid+1,r);
}
void update(int num,int t,int val)
{
	if(segTree[num].l==segTree[num].r)
	{
		if(val==1) segTree[num].ls=segTree[num].rs=segTree[num].maxs=1;
		else  segTree[num].ls=segTree[num].rs=segTree[num].maxs=0;
		return;
	}
	int mid=(segTree[num].l+segTree[num].r)>>1;
	if(t<=mid) update(num<<1,t,val);
	else update((num<<1)|1,t,val);
	
	segTree[num].ls=segTree[num<<1].ls;
	segTree[num].rs=segTree[(num<<1)|1].rs;
	segTree[num].maxs=max(segTree[num<<1].maxs,segTree[(num<<1)|1].maxs);
	segTree[num].maxs=max(segTree[num].maxs,segTree[num<<1].rs+segTree[(num<<1)|1].ls);
	
	if(segTree[num<<1].ls==segTree[num<<1].r-segTree[num<<1].l+1)
	   segTree[num].ls+=segTree[(num<<1)|1].ls;
	if(segTree[num<<1|1].rs==segTree[num<<1|1].r-segTree[(num<<1)|1].l+1)
	   segTree[num].rs+=segTree[num<<1].rs;      
}
int query(int num,int t)
{
          //多了個剪枝,如果一個區間的最大連續區間為0,或等於區間長度,則返回
         if(segTree[num].l==segTree[num].r||segTree[num].maxs==0||segTree[num].maxs==segTree[num].r-segTree[num].l+1)
	  return segTree[num].maxs;
	int mid=(segTree[num].l+segTree[num].r)>>1;
	
	if(t<=mid)
	{
                   //t在左子樹的rs裡,能右子樹的ls相連
              if(t>=segTree[num<<1].r-segTree[num<<1].rs+1)
		 return query(num<<1,t)+query(num<<1|1,mid+1);
		else return query(num<<1,t);   
	}
	else
	{
                   //同理
              if(t<=segTree[num<<1|1].l+segTree[num<<1|1].ls-1)
		 return query(num<<1|1,t)+query(num<<1,mid);
		else 
		   return query(num<<1|1,t);   
	}    
}
int stack[MAXN];
int main(void)
{
	int n,m;
	int t;
	char op[2];
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		build(1,1,n);
		int top=0;
		while(m--)
		{
			scanf("%s",op);
			if(op[0]=='D')
			{
				scanf("%d",&t);
				stack[top++]=t;
				update(1,t,0);
			}
			else if(op[0]=='Q')
			{
			    scanf("%d",&t);
			    printf("%d\n",query(1,t));
			}
			else{
				if(t>0)
				{
					t=stack[--top];
					update(1,t,1);
				}
			}
		}
	}
	return 0;
}