HDU 1540 Tunnel Warfare

  这题是数据结构题,用线段树做,设置两个数组,记录节点最大左连续值,节点右最大连续值,输出便有三种情况,节点左最大连续值,节点右最大连续值,和兄弟节点之间左右最大连续值相加,注意,此题有个坑,坑了我好久,输入时不止一组数据,要用while(!=EOF)来写.
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm> 
#include <stack>
#define maxn 50000
#define mem(a) memset(a, 0, sizeof(a))
using namespace std;

long lv[maxn * 4 + 5], rv[maxn * 4 + 5], nl[maxn * 4 + 5], nr[maxn * 4 + 5], flag, num;

void build(long l, long r, long n)
{
	nl[n] = l;
	nr[n] = r;
	if(l == r)
	{
		lv[n] = 1;
		rv[n] = 1;
		return;
	}
	long mid = (l + r) / 2;
	build(l, mid, n * 2);
	build(mid + 1, r, n * 2 + 1);
	rv[n] = lv[n] = lv[n * 2] + lv[n * 2 + 1];
}

void des(long l, long r, long n, long ll)
{
	if(l == r&&l == ll)
	{
		lv[n] = 0;
		rv[n] = 0;
		return;
	}
    long mid = (l + r) / 2;
	if(ll <= mid)
	des(l, mid, n * 2, ll);
	else
	des(mid + 1, r, n * 2 + 1, ll);
	if(rv[n * 2 + 1] == lv[n * 2 + 1]&&rv[n * 2 + 1] == (nr[n * 2 + 1] - nl[n * 2 + 1] + 1))
	rv[n] = rv[n * 2 + 1] + rv[n * 2];
	else
	rv[n] = rv[n * 2 + 1];
	if(rv[n * 2] == lv[n * 2]&&rv[n * 2] == (nr[n * 2] - nl[n * 2] + 1))
	lv[n] = lv[n * 2] + lv[n * 2 + 1];
	else
	lv[n] = lv[n * 2];
}

void rbt(long l, long r, long n, long ll)
{
	if(l == r&&l == ll)
	{
		lv[n] = 1;
		rv[n] = 1;
		return;
	}
    long mid = (l + r) / 2;
	if(ll <= mid)
	rbt(l, mid, n * 2, ll);
	else
	rbt(mid + 1, r, n * 2 + 1, ll);
	if(rv[n * 2 + 1] == lv[n * 2 + 1]&&rv[n * 2 + 1] == (nr[n * 2 + 1] - nl[n * 2 + 1] + 1))
	rv[n] = rv[n * 2 + 1] + rv[n * 2];
	else
	rv[n] = rv[n * 2 + 1];
	if(rv[n * 2] == lv[n * 2]&&rv[n * 2] == (nr[n * 2] - nl[n * 2] + 1))
	lv[n] = lv[n * 2] + lv[n * 2 + 1];
	else
	lv[n] = lv[n * 2];
}

void que(long l, long r, long n, long ll)
{
	if(flag == 1)
	return;
	if((lv[n] + nl[n] - 1) >= ll)
	{
		if(l != 1&&rv[n - 1])
		{
			printf("%ld\n",lv[n] + rv[n - 1]);
		    flag = 1;
		    return;
		}
		printf("%ld\n", lv[n]);
		flag = 1;
		return;
	}
	if((nr[n] - rv[n] + 1) <= ll)
	{
		if(r != num&&lv[n + 1])
		{
			printf("%ld\n",rv[n] + lv[n + 1]);
		    flag = 1;
		    return;
		}
		printf("%ld\n",rv[n]);
		flag = 1;
		return;
	}
	if(l == r)
	return;
	long mid = (l + r) / 2;
	if(ll <= mid)
	que(l, mid, n * 2, ll);
	else
	que(mid + 1, r, n * 2 + 1, ll);
}

int main(int argc, char *argv[])
{
	int i, j;
	long q, a;
	char ch;
	stack<long> st;
	while(scanf("%ld%ld%*c", &num, &q) != EOF)
	{
	    mem(lv);
	    mem(rv);
	    mem(nl);
	    mem(nr);
	    while(!st.empty())
	    {
    		st.pop();
    	}
	    build(1, num, 1);
	    for(i = 0;i < q;i++)
	    {
		    scanf("%c", &ch);
		    if(ch == 'D')
		    {
			    scanf("%ld%*c", &a);
			    des(1, num, 1, a);
			    st.push(a);
		    }
		    else if(ch == 'Q')
		    {
			    flag = 0;
			    scanf("%ld%*c", &a);
			    que(1, num, 1, a);
			    if(!flag)
			    printf("0\n");
		    }
		    else if(ch == 'R')
		    {
			    scanf("%*c");
			    a = st.top();
			    st.pop();
			    rbt(1, num, 1, a);
		    }
	    }
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值