HDU1540:线段树

本文详细解析HDU1540题目的解题思路,通过维护区间的最大值和最小值,实现快速查找区间内最大连续未破坏点的数量。采用线段树数据结构进行高效更新和查询。

HDU1540

题意:求区间最大连续点的个数

题解:

  • 我们要找某个点,那么就要找到左边最近被破坏(在左边编号是最大的)maxd的和右边最近被破坏的(在右边编号是最小的)mind,那么ans = min - max - 1

  • 所以维护区间的最大值和最小值

  • 默认最大值是0,最小值是n+1

  • 每次破坏了之后这个点的最大值和最小值就更新成它本身

  • 特殊情况下询问的是被破坏的点,那么就是0(特判)

代码:

#include <bits/stdc++.h>
using namespace std;
int const N = 50000 + 10;
int const inf = 0x7f7f7f7f;
int n,m,last[N],tot;
struct Node
{
	int l,r,maxd,mind;
}node[N<<2];
void build(int id,int l,int r){
	node[id].l = l,node[id].r = r;
	if(l == r){
		node[id].maxd = 0,	node[id].mind = n+1;
	}else{
		int mid = (l + r) >> 1;
		build(id<<1,l,mid);
		build(id<<1|1,mid+1,r);
		node[id].maxd = max(node[id<<1].maxd,node[id<<1|1].maxd);
		node[id].mind = min(node[id<<1].mind,node[id<<1|1].mind);
	}
}
void updata_min(int id,int pos,int k){
	int l = node[id].l,	r = node[id].r;
	if(l == r){
		node[id].mind = k;
	}else{
		int mid = (l + r) >> 1;
		if(pos <= mid)	updata_min(id<<1,pos,k);
		else 	updata_min(id<<1|1,pos,k);
		node[id].mind = min(node[id<<1].mind,node[id<<1|1].mind);
	}
}
void updata_max(int id,int pos,int k){
	int l = node[id].l,	r = node[id].r;
	if(l == r){
		node[id].maxd = k;
	}else{
		int mid = (l + r) >> 1;
		if(pos <= mid)	updata_max(id<<1,pos,k);
		else 	updata_max(id<<1|1,pos,k);
		node[id].maxd = max(node[id<<1].maxd,node[id<<1|1].maxd);
	}
}
int query_max(int id,int L,int R){  
	int l = node[id].l,	r = node[id].r;
	if(L <= l && r <= R){
		return node[id].maxd;
	}else{
		int mid = (l + r) >> 1;
		int maxd = 0;
		if(L <= mid)	maxd = max(maxd,query_max(id<<1,L,R));
		if(mid < R) 	maxd = max(maxd,query_max(id<<1|1,L,R));
		return maxd;
	}
}
int query_min(int id,int L,int R){  
	int l = node[id].l,	r = node[id].r;
	if(L <= l && r <= R){
		return node[id].mind;
	}else{
		int mid = (l + r) >> 1;
		int mind = inf;
		if(L <= mid)	mind = min(mind,query_min(id<<1,L,R));
		if(mid < R) 	mind = min(mind,query_min(id<<1|1,L,R));
		return mind;
	}
}
int main(){
	while(~	scanf("%d%d",&n,&m)){
		tot = 0;
		build(1,1,n);
		for(int i=1;i<=m;i++){
			char c;
			int x;
			scanf(" %c",&c);
			if(c == 'D'){
				scanf("%d",&x);
				last[++tot] = x;
				updata_min(1,x,x);   //x位置变成x本身
				updata_max(1,x,x);
			}else if(c == 'Q'){
				scanf("%d",&x);
				int mind = query_min(1,x,n);   //询问[x,n]的最小值
				int maxd = query_max(1,1,x);   //询问[1,x]的最大值
				if(mind == maxd)	printf("%d\n",0);
				else	printf("%d\n",mind-maxd-1);
			}else{
				int tmp = last[tot--];
				updata_min(1,tmp,n+1);
				updata_max(1,tmp,0);
			}
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值