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和m,表示有n个村庄和m个操作,n个村庄在一条直线上;操作有三种:
(1)输入子符D:毁坏村庄i;
(2)输入字符Q:询问与i村庄相通的村庄一共有多少个;
(3)输入字符R:修复最近一次毁坏且没有修复的村庄;

心得:
这道题我看着这个样子就是用线段树做,但是当我写到数据更新的时候我就卡住了,后来又在查询那里卡住了,我不知道更新那里为什么那么写,但这样写就是对的,这里不得不说句“牛批啊!”,而查询那里倒理解了为什么那样写!还要多多学习啊!

解析:
这里用到了结构体,也可以多弄俩数组,lsum表示从区间的左端点开始的连通村庄数,rsum表示从区间右端点开始的连通村庄数,sum记录的是区间内最大的连通村庄数(因为区间可能被分成多段)。
跟新函数updata()没什么好说的,但是pushup()函数就得说说:
我们从最极限说起,即m为2,则tree[i<<1].lsum=tree[i<<1].rsum=tree[i<<1].sum=1;
tree[i<<1|1].lsum=tree[i<<1|1].rsum=tree[i<<1|1].sum=1;
tree[i<<1].lsum==m-(m>>1),所以tree[i].lsum=tree[i<<1].lsum+tree[i<<1|1].lsum,也就是m.
同理,tree[i<<1|1].rsum也是一样,所以往上推也都是对的!

然后是查询函数:
由于tree[i].lsum和tree[i].rsum分别记录的是区间包含端点的最大连通村庄数,所以当区间中点mid=(l+r)>>1,当被查询点到中点的距离大于中点两侧最大的连通数(即包含中点的连通村庄数),就继续往下查询!

代码:

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#define N 50005

using namespace std;

struct node{
	int lsum,rsum,sum;
}; 

node tree[N<<2];
stack<int>list;

void pushup(int i,int m)
{
	tree[i].lsum=tree[i<<1].lsum;
	tree[i].rsum=tree[i<<1|1].rsum;
	if(tree[i].lsum==(m-(m>>1)))
		tree[i].lsum+=tree[i<<1|1].lsum;
	if(tree[i].rsum==(m>>1))
		tree[i].rsum+=tree[i<<1].rsum;
	tree[i].sum=max(tree[i<<1].sum,tree[i<<1|1].sum);
	tree[i].sum=max(tree[i].sum,tree[i<<1].rsum+tree[i<<1|1].lsum);
}

void build(int l,int r,int i)
{
	if(l==r)
	{
		tree[i].lsum=tree[i].rsum=tree[i].sum=1;
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,i<<1);
	build(mid+1,r,i<<1|1);
	pushup(i,r-l+1);
}

void updata(int l,int r,int i,int x,int type)
{
	if(l==r)
	{
		tree[i].lsum=tree[i].rsum=tree[i].sum=type?1:0;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)
		updata(l,mid,i<<1,x,type);
	else
		updata(mid+1,r,i<<1|1,x,type);
	pushup(i,r-l+1);
}

int query(int l,int r,int i,int x)
{
	if(l==r||tree[i].sum==(r-l+1)||tree[i].sum==0)
		return tree[i].sum;
	int mid=(l+r)>>1;
	if(x<=mid)
	{
		if(x>=mid-tree[i<<1].rsum+1)
			return tree[i<<1].rsum+tree[i<<1|1].lsum;
		else
			return query(l,mid,i<<1,x);
	}
	else
	{
		if(x<=tree[i<<1|1].lsum+mid)
			return tree[i<<1].rsum+tree[i<<1|1].lsum;
		else
			return query(mid+1,r,i<<1|1,x);
	}
}

int main()
{
	int n,m,x;
	char c;
	while(~scanf("%d%d",&n,&m))
	{
		build(1,n,1);
		for(int i=1;i<=m;i++)
		{
			scanf("%*c%c",&c);
			switch(c)
			{
				case 'D':
					scanf("%d",&x);
					updata(1,n,1,x,0);
					list.push(x);
					break;
				case 'Q':
					scanf("%d",&x);
					printf("%d\n",query(1,n,1,x));
					break;
				case 'R':
					if(!list.empty())
					{
						x=list.top();
						list.pop();
						updata(1,n,1,x,1);
					}
					break;
			}
		}
		while(!list.empty())
		{
			list.pop();
		}
	}
	return 0;
 }
发布了46 篇原创文章 · 获赞 16 · 访问量 409

猜你喜欢

转载自blog.csdn.net/weixin_43357583/article/details/105060157