线段树最大连续区间 -- Tunnel Warfare HDU - 1540

题意:
n个点,m个操作(1<=n,m<=5e4),m行中每行一个字符c表示操作类型,一个整型数x表示第x个点

D x 表示去掉第x点,Q x表示需输出含 x 的最大连续区间的长度,R x表示还原最后去掉的点

思路:
第一种思路:利用线段树求解, 线段树维护一个最长连续子段和,然后查询的时候判断x点是在左边区间还是右边区间,如果在左边区间就判断左边区间的rmax(包含右断点的最大连续子段和)的长度是否超过了x那个点,如果超过了那么直接返回 左边区间.rl + 右边区间.ll。 否则继续查询左边区间。x在右边区间同理。

code:

#include <bits/stdc++.h>
using namespace std;
struct node
{
	int ll,rl,ml;
}tree[50005*4];
int n,m,x;
char c;
stack<int> sk;
void build(int l,int r,int rt)
{
	tree[rt].ll=tree[rt].rl=tree[rt].ml=r-l+1;
	if(l==r) return;
	build(l,(l+r)/2,rt<<1);
	build((l+r)/2+1,r,rt<<1|1);
}
void update(int x,int c,int l,int r,int rt)
{
	if(x<l||x>r) return;
	if(l==r) 
	{
		tree[rt].ll=tree[rt].rl=tree[rt].ml=c;
		return;
	}
	update(x,c,l,(l+r)/2,rt<<1);
	update(x,c,(l+r)/2+1,r,rt<<1|1);
	//最大连续长度是 1.左儿子最大长 2.右儿子最大长 3.左儿子右边界+右儿子左边界最大长 之一 
    tree[rt].ml=max(max(tree[rt<<1].ml,tree[rt<<1|1].ml),tree[rt<<1].rl+tree[rt<<1|1].ll);
	tree[rt].ll=tree[rt<<1].ll;//最大左长为左儿子左长,若左儿子左长满区间,则要加右儿子左长 
	if(tree[rt].ll==(l+r)/2-l+1) tree[rt].ll+=tree[rt<<1|1].ll;
	tree[rt].rl=tree[rt<<1|1].rl;//最大右长同理 
	if(tree[rt].rl==r-(l+r)/2) tree[rt].rl+=tree[rt<<1].rl;
}
int query(int x,int l,int r,int rt)
{
	//叶子结点 或 完全连续 或 完全不连续     
	if(l==r||tree[rt].ml==r-l+1||!tree[rt].ml) return tree[rt].ml;
	if(x<(l+r)/2+1-tree[rt<<1].rl) return query(x,l,(l+r)/2,rt<<1);//在中间地带左侧 
	if(x>(l+r)/2+tree[rt<<1|1].ll) return query(x,(l+r)/2+1,r,rt<<1|1);//在中间地带右侧 
	return tree[rt<<1].rl+tree[rt<<1|1].ll;//在中间地带直接返回加合 
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		build(1,n,1);
		while(m--)
		{
			getchar();
			scanf("%c",&c);
			if(c=='D') scanf("%d",&x),update(x,0,1,n,1),sk.push(x);
			else if(c=='R') update(sk.top(),1,1,n,1),sk.pop();
			else scanf("%d",&x),printf("%d\n",query(x,1,n,1));
		}
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值