HDU - 1540 Tunnel Warfare (线段树+二分)

Tunnel Warfare

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


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个城市,他们彼此之间按照序号由铁路相连。

    现在有m个询问。询问有三种。

1、D  x  表示第X个城镇被炸弹炸毁

2、Q  x  表示询问与第X个城市仍然相连的城市数量,并输出。

扫描二维码关注公众号,回复: 1890241 查看本文章

3、R      表示上一个被炸毁的城市现在被复原了


三、思路

     我们使用线段树储存n个城市是否被炸毁的信息,被炸毁的城市用0表示,完好的城市用1表示。那么对应的三种询问,则:

1、对于炸毁的操作,我们只需要更新点的信息为0,并且用一个模拟的栈Stack来记录炸毁的顺序。

2、对于复原的操作,我们也只需要弹出栈顶元素,并更新该点为1即可。

3、对于询问与x城市相连城市的数量,实际上就是查找该城镇左右两边的仍没有没炸毁的最大的段是多少。所以可以先二分比如左边段上的某点 j,若段[ j , x ] 上的和为x-j+1,那么就是说明这一段中间是没有被断掉的城市的。反之,若不等于x-j+1则说明中间必定有点是被修改为0的,这样就构成了二分的条件。那么我们二分左右两端得到两个点 tl , tr, 那么tr-tl+1就是所求了。


四、代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<list>
using namespace std;
const int INF = 0x3f3f3f3f;
#define LL long long int 
#define PI 3.14159265
long long  gcd(long long  a, long long  b) { return a == 0 ? b : gcd(b % a, a); }


int n, q;
const int maxn = 50005 * 4;	
struct Tree
{
	int l, r, sum;
};
Tree node[maxn];		
int a[maxn];			
void update(int i)
{
	node[i].sum = node[i << 1].sum + node[(i << 1) | 1].sum;
}
void build(int i, int l, int r)
{
	node[i].l = l; node[i].r = r;
	if (l == r)
	{
		node[i].sum = 1;
		return;
	}
	int mid = (l + r) / 2;
	build(i << 1, l, mid);
	build((i << 1) | 1, mid + 1, r);
	update(i);
}
int getsum(int i, int l, int r)
{
	if (node[i].l == l&&node[i].r == r)
		return node[i].sum;
	int mid = (node[i].l + node[i].r) / 2;
	if (r <= mid) return getsum(i << 1, l, r);
	else if (l > mid) return getsum((i << 1) | 1, l, r);
	else return getsum(i << 1, l, mid) + getsum((i << 1) | 1, mid + 1, r);
}

void add(int i, int k, int v)	
{
	if (node[i].l == k&&node[i].r == k)
	{
		node[i].sum = v;
		return;
	}
	int mid = (node[i].l + node[i].r) / 2;
	if (k <= mid) add(i << 1, k, v);
	else add((i << 1) | 1, k, v);
	update(i);
}
int main()
{
	while (scanf("%d%d", &n, &q) != EOF)
	{
		build(1, 1, n);
		char t[3];
		int p;
		int Stack[50005];
		int top = 0;
		while (q--)
		{
			scanf("%s", t);
			if (t[0] == 'D')
			{
				scanf("%d", &p);
				add(1, p, 0);
				Stack[top++] = p;
			}
			else if (t[0] == 'R')
			{
				top--;
				add(1, Stack[top], 1);
			}
			else if (t[0] == 'Q')
			{
				scanf("%d", &p);
				if (getsum(1, p, p) == 0)
				{
					printf("0\n");
					continue;
				}
				int tl, tr;
				int l = p, r = n;
				int mid;
				tr = p;
				while (l <= r)        //二分右端点
				{
					mid = (l + r) / 2;
					if (getsum(1, p, mid) != (mid - p + 1))
						r = mid - 1;
					else
					{
						l = mid + 1;
						tr = mid;
					}
				}


				l = 1, r = p;
				tl = p;
				while (l <= r)        //二分左端点
				{
					mid = (l + r) / 2;
					if (getsum(1, mid, p) != (p - mid + 1))
						l = mid + 1;
					else
					{
						tl = mid;
						r = mid - 1;
					}
				}

				if (tr >= tl)
					printf("%d\n", tr - tl + 1);
				else
					printf("0\n");
			}
		}

	}
	
	getchar();
	getchar();
}

猜你喜欢

转载自blog.csdn.net/amovement/article/details/80686703
今日推荐