hdu 1540 Tunnel Warfare

题目大意:

给你一段连续村庄,D x表示破坏第x个村庄,Q x为包括x在内的连续的好的村庄有多少,R 为修复最后一个破坏的村庄;

解题思路:

这是一道线段树类的的题目,包括区间的合并和单点更新,对于重建最后一个被破坏的村庄,我们可以用一个stack来存储破坏掉的村庄。
难点在于对连续好的村庄统计,我们在统计的时候要判断
1:如果x在当前结点的左孩子范围内
如果它在右连续区间,则要不仅要加上右连续区间还要加上父亲的右孩子的左连续区间;
不在右连续区间,则直接递归左孩子即可;
2:在右孩子范围内则要考虑是不是在左连续区间;
看了网上的几篇博客,发现在加上另一个区间的时候还要去递归,实际没必要,直接加和node【k】.ls或者node【k】.rs即可;其次我也亲测了判断query递归条件结束时候用如果都是1或者都是0的那个判断,实际上效果并不好,反而用时更长;
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;

#define maxn 100010
#define L(a) (a)<<1
#define R(a) (a)<<1|1

struct Node{
	int lc,rc;
	int len;
	int ls,ms,rs;
}node[3*maxn];

void pushup(int k)
{
	node[k].ls=node[L(k)].ls;
	node[k].rs=node[R(k)].rs;
	if(node[L(k)].ls==node[L(k)].len)
	node[k].ls+=node[R(k)].ls;
	if(node[R(k)].rs==node[R(k)].len)
	node[k].rs+=node[L(k)].rs;
	node[k].ms=max(max(node[L(k)].ms,node[R(k)].ms),node[L(k)].rs+node[R(k)].ls);
}

void create(int k,int l,int r)
{
	node[k].lc=l;
	node[k].rc=r;
	node[k].len=r-l+1;
	node[k].ls=node[k].rs=node[k].ms=node[k].len;
	if(l==r)
	return ;
	int mid=(l+r)>>1;
	create(L(k),l,mid);
	create(R(k),mid+1,r);
}

void updata(int k,int x,int op)
{
	if(node[k].lc==x&&node[k].rc==x)
	{
		node[k].ls=node[k].rs=node[k].ms=op;
		return ;
	}
	int mid=(node[k].lc+node[k].rc)>>1;
	if(x<=mid)
	updata(L(k),x,op);
	else
	updata(R(k),x,op);
	pushup(k);
}

int query(int k,int x)
{
	if(node[k].lc==node[k].rc)
	{
		return node[k].ls;
	}
	int mid=(node[k].lc+node[k].rc)>>1;
	int ans=0;
	if(x<=mid)
	{
		if(x>=node[L(k)].rc-node[L(k)].rs+1)
		{
			ans+=node[L(k)].rs+node[R(k)].ls;
		}
		else
		ans+=query(L(k),x);
	}
	else
	{
		if(x<=node[R(k)].ls+node[R(k)].lc-1)
		{
			ans+=node[R(k)].ls+node[L(k)].rs;
		}
		else
		ans+=query(R(k),x);
	}
	return ans;
}
int main()
{
	int n,m;
	//freopen("input.txt","r",stdin);
	while(~scanf("%d%d",&n,&m))
	{
		stack<int> q;
		while(!q.empty()) q.pop();
		create(1,1,n);
		char s[10];
		int op;
		for(int i=0;i<m;i++)
		{
			scanf("%s%d",s,&op);
			if(s[0]=='D')
			{
				updata(1,op,0);
				q.push(op);
			}
			else if(s[0]=='Q')
			{
				int ans=query(1,op);
				printf("%d\n",ans);
			}
			else
			{
				int t=q.top();
				q.pop();
				updata(1,t,1);
			}
		}
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值