HDU1540 Tunnul Warfare 线段树

题意:大意是给你成线性排列的一个村庄,有如下三种操作:
摧毁某一村庄。询问某一村庄所连接的最多村庄数。修复最近被摧毁的村庄。

——————————————————————
19.9.12重写发现最大的坑是,题目是单组,其实应该是多组输入!!!
——————————————————————
思路:典型的线段树处理。单点修改,区间查询,查询内容不是简单的求和,而是求目标点所在区间的最大连续长度。我们需要用到三个变量:lmax rmax mmax,分别对应当前区间从左端开始的、右端开始的、中间开始的最长连续区间。所以updata函数还是很好写的,主要是下面的query函数:
1、若询问到的区间是单点、或者全空或者全满,说明可以直接返回(想想为什么)
2、若不是以上情况,就看看是不是在中间一段连续区间里。不是的话再去搜左右子树。

int query(int k,int p) {
	if(t[k].l==t[k].r||t[k].mmax==0||t[k].mmax==t[k].r-t[k].l+1) {
		//若到了叶结点或全满或全空  就说明那个点就在当前这个区间里
		return t[k].mmax;
	} else {
		int mid=(t[k].l+t[k].r)>>1;
		if(p<=mid) { //若询问的点在左子树
			if(p>=t[k<<1|1].l-t[k<<1].rmax){//若包含在中间一段的连续区间里面 
				return t[k<<1].rmax+t[k<<1|1].lmax;
			}
			else return query(k<<1,p);
		}
		if(p>mid) {
			if(p<=t[k<<1].r+t[k<<1|1].lmax){//若包含在中间一段的连续区间里面 
				return t[k<<1].rmax+t[k<<1|1].lmax;
			}
			else return query(k<<1|1,p);
		}
	}
}

下面是AC代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<queue>
#define ll long long
#define maxn 50005
using namespace std;//求 从询问位置所在的最长子串
struct node {         //左边开始的最大值,右边开始的  中间一部分的  从这点开始的最大值
	int l,r,lmax,rmax,mmax;//单点修改 不需要lazy
} t[maxn<<2];
void pushup(int k) {
	t[k].lmax=t[k<<1].lmax;
	t[k].rmax=t[k<<1|1].rmax;
	if(t[k].lmax==t[k<<1].r-t[k<<1].l+1)
		t[k].lmax+=t[k<<1|1].lmax;
	if(t[k].rmax==t[k<<1|1].r-t[k<<1|1].l+1)
		t[k].rmax+=t[k<<1].rmax;
	//这下面你写错了  应该是两个子树的最大!!!
	t[k].mmax=max(max(t[k<<1].mmax,t[k<<1|1].mmax),t[k<<1].rmax+t[k<<1|1].lmax);
	return;
}
void build(int k,int l,int r) {
	t[k].l=l,t[k].r=r;
	if(l==r) {
		t[k].mmax=t[k].lmax=t[k].rmax=1;//1
	} else {
		int mid=(l+r)>>1;
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		pushup(k);
	}
}
void updata(int k,int p,int v) { //把p位置更新成v
	if(t[k].l==t[k].r) {
		if(t[k].l==p) { //若就是这个点
			t[k].mmax=t[k].lmax=t[k].rmax=v;
		}
		return;//如果不是 就return
	} else {
		int mid=(t[k].l+t[k].r)>>1;
		if(p<=mid) updata(k<<1,p,v);
		if(p>mid) updata(k<<1|1,p,v);
		pushup(k);
	}
}
int query(int k,int p) {
	if(t[k].l==t[k].r||t[k].mmax==0||t[k].mmax==t[k].r-t[k].l+1) {
		//若到了叶结点或全满或全空  就说明那个点就在当前这个区间里
		return t[k].mmax;
	} else {
		int mid=(t[k].l+t[k].r)>>1;
		if(p<=mid) { //若询问的点在左子树
			if(p>=t[k<<1|1].l-t[k<<1].rmax) return t[k<<1].rmax+t[k<<1|1].lmax;
			else return query(k<<1,p);
		}
		if(p>mid) {
			if(p<=t[k<<1].r+t[k<<1|1].lmax) return t[k<<1].rmax+t[k<<1|1].lmax;
			else return query(k<<1|1,p);
		}
	}
}
int main() {
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF) {
		stack<int> stk;
		build(1,1,n);
		while(m--) {
			char s[3];
			scanf("%s",s);
			int p;
			if(s[0]=='D') { //destroy
				scanf("%d",&p);
				stk.push(p);
				updata(1,p,0);
			}
			if(s[0]=='Q') {
				scanf("%d",&p);
				printf("%d\n",query(1,p));
			}
			if(s[0]=='R') {
				if(!stk.empty()) {
					updata(1,stk.top(),1);
					stk.pop();
				}
			}
		}
	}
	return 0;
}
 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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值