线段树维护最长连续区间 hdu 1540 Tunnel Warfare

链接: link.
题意:

输入n表示n个城市,输入m表示m个操作,有3中操作:
1、D x 表示摧毁第x个城市
2、Q x 表示查询包括x村庄的连续的没被摧毁的城市个数
3、R 表示修复上一个被摧毁的城市

思路:

对于每个,1表示城市没被摧毁,0表示摧毁,对于每个区间lmax表示从区间最左边开始的连续城市,rmax表示从区间最右边开始的连续城市数量,maxx表示该区间的最大连续区间。
每次摧毁城市的时候,找到那个城市,改为0,然后pushup。
pushup函数中当前区间的lmax=左儿子区间的lmax,如果左儿子区间的lmax==左儿子区间的城市数量,那么当前区间的值还要加上右儿子区间的lmax,同理rmax也是这样(具体看代码)。
对于maxx,就等于左儿子的maxx和右儿子的maxx和左儿子的rmax+右儿子的lmax三者的最大值

代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
#include <queue>
#include <vector>
#define ll long long
#define T int T;scanf("%d", &T);while(T--)
#define inf 0x7f7f7f7f
using namespace std;
const int maxn = 1000100;
struct node{
	ll lmax,rmax;
	int l,r;
	ll maxx;
}tree[maxn<<2];
ll a[maxn];
int n,m;
void pushup(int index){
	tree[index].lmax = tree[index*2].lmax;
	if(tree[index*2].lmax==tree[index*2].r-tree[index*2].l+1){	//如果左区间整个都是好的城市,那么index这个区间的lmax要加上右儿子的lmax
		tree[index].lmax += tree[index*2+1].lmax;
	}
	tree[index].rmax = tree[index*2+1].rmax;
	if(tree[index*2+1].rmax==tree[index*2+1].r-tree[index*2+1].l+1){ //如果有区间整个都是好的城市,那么index这个区间的rmax要加上左儿子的rmax
		tree[index].rmax += tree[index*2].rmax; 
	}
	tree[index].maxx = max(max(tree[index*2].maxx,tree[index*2+1].maxx),tree[index*2].rmax+tree[index*2+1].lmax);
}
void build(int l,int r,int index){
	tree[index].l = l;
	tree[index].r = r;
	if(l==r){
		tree[index].lmax=tree[index].rmax=tree[index].maxx=1; //刚开始都是好的城市
		return;
	}
	int mid = (l+r)/2;
	build(l,mid,index*2);
	build(mid+1,r,index*2+1);
	pushup(index);
}
void update(int w,int p,int index){
	if(tree[index].l==tree[index].r){
		tree[index].lmax=tree[index].rmax=tree[index].maxx=w; //改变城市状态
		return;
	}
	int mid = (tree[index].l+tree[index].r)/2;
	if(p<=mid) update(w,p,index*2);	//二分找城市
	else update(w,p,index*2+1);
	pushup(index);
}
ll query(int p,int index){
	if(tree[index].maxx==0 || tree[index].l==tree[index].r){ //如果找到城市或者最长连续区间已经是0
		return tree[index].maxx;
	}
	ll ans = 0;
	int mid = (tree[index].l+tree[index].r)/2;
	if(p<=mid){	
		if(mid-p+1<=tree[index*2].rmax)	//如果左儿子的rmax包含了p点,那么直接加上右儿子的lmax
			ans += tree[index*2].rmax+tree[index*2+1].lmax;
		else ans += query(p,index*2);	//否则搜索左儿子区间
	}
	else{
		if(p-mid<=tree[index*2+1].lmax)	//同理
			ans += tree[index*2].rmax+tree[index*2+1].lmax;
		else ans += query(p,index*2+1);
	}
	return ans;
}

int main(){
	int tt = 1;
	int x,y,z;
	int ss[100000];
	int last = 0;
	while(~scanf("%d", &n)){
		build(1,n,1);
		scanf("%d", &m);
		while(m--){
			char c;
			cin >> c;
			if(c=='D'){
				scanf("%d", &x);
				ss[++last] = x;
				update(0,x,1);	//破坏城市,把x变为0
			}else if(c=='Q'){
				scanf("%d", &x);
				printf("%lld\n",query(x,1));
			}else{
				update(1,ss[last--],1);	修城市,把上一个破坏的城市变成1
			}
		}
		printf("\n");
	}
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值