POJ-2892/HDU-1540 Tunnel Warfare (树状数组+二分查找)

这两道题的题目时一样的,但是数据不一样。

bool d[maxn]; 用于记录村庄i是否被炸毁

建立一个树状数组bit[maxn],sum(i)用于计算[1,i]区间内被摧毁的村庄的个数

stack<int> 记录被炸毁的村庄的顺序

下面对三种指令进行处理

首先对数据做一点说明:POJ的数据中应该没有继续炸毁已经被炸毁村庄的操作,但是HDU的数据中有

1. D x   摧毁x村庄 对于POJ 的数据,直接压栈,修改标记,维护树状数组,完事

                               对于HDU的数据,需要压栈,然后判断标记,如果为假,即村庄此时尚未被炸毁那就修改标记,维护树状数组

                               如果为真,即村庄已经是被炸毁的,就不进行压栈外的其他操作

2. R 从栈中取出最近一个被炸毁的村庄  对于poj数据来说,直接取栈顶元素;对于hdu,则需先将栈顶的标记为假元素出栈,处理                                                                    第一个标记为真的元素。操作是弹栈,修改标记维护树状数组

3.Q x 如果x标记为真,输出0;

          x标记为假,计算v=sum(x),bs(x,n+1,v+1)得到sum(i)为v+1,的第一个i,也正因为如果sum(x)就是当前的最大值,需要              设置n+1为终点;bs(0,t,v)这里起点设置为0 是为了统一操作。二者的差就是sum(i)==v的所有i的数量,再减去第一个                sum(i)==v处的村庄被炸毁(v==0已经特殊处理),就是x能联系到的村庄数

POJ版本程序

#include<cstdio> 
#include<cstring>
#include<stack>
#define maxn 50005
using namespace std;
bool d[maxn];
int bit[maxn],n,m;
stack<int> s;
inline int lowbit(int i)
{
	return i&-i;
}
int sum(int x)
{
	int s=0;
	for(int i=x;i;i-=lowbit(i)) s+=bit[i];
	return s;
}
void add(int x,int v)
{
	for(int i=x;i<=n;i+=lowbit(i))
		bit[i]+=v;
}
int bs(int l,int r,int v)
{
	int mid;
	while(l<r)
	{
		mid=(l+r)/2;
		if(sum(mid)>=v) r=mid;
		else l=mid+1;
	}
	return l;
}
int main()
{
	char q[10]; int t;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(bit+1,0,sizeof(int)*n);
		memset(d+1,0,sizeof(bool)*n);
		while(!s.empty()) s.pop();
		for(int i=0;i<m;i++)
		{
			scanf("%s",q);
			if(q[0]=='D')
			{
				scanf("%d",&t);
				d[t]=true;
				s.push(t);
				add(t,1);
			}
			else if(q[0]=='R')
			{
				d[s.top()]=false;
				add(s.top(),-1);
				s.pop();
			}
			else
			{
				scanf("%d",&t);
				if(d[t]) printf("0\n");
				else 
				{
					int v=sum(t);
					printf("%d\n",bs(t,n+1,v+1)-bs(0,t,v)-1);
				}
			}
		}
	}
	return 0;
}

HDU版本程序

#include<cstdio> 
#include<cstring>
#include<stack>
#define maxn 50005
using namespace std;
bool d[maxn];
int bit[maxn],n,m;
stack<int> s;
inline int lowbit(int i)
{
	return i&-i;
}
int sum(int x)
{
	int s=0;
	for(int i=x;i;i-=lowbit(i)) s+=bit[i];
	return s;
}
void add(int x,int v)
{
	for(int i=x;i<=n;i+=lowbit(i))
		bit[i]+=v;
}
int bs(int l,int r,int v)
{
	int mid;
	while(l<r)
	{
		mid=(l+r)/2;
		if(sum(mid)>=v) r=mid;
		else l=mid+1;
	}
	return l;
}
int main()
{
	char q[10]; int t;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(bit+1,0,sizeof(int)*n);
		memset(d+1,0,sizeof(bool)*n);
		while(!s.empty()) s.pop();
		for(int i=0;i<m;i++)
		{
			scanf("%s",q);
			if(q[0]=='D')
			{
				scanf("%d",&t);
				s.push(t);
				if(!d[t])
				{
					d[t]=true;
					add(t,1);
				}
			}
			else if(q[0]=='R')
			{
				while(!d[s.top()]) s.pop();
				d[s.top()]=false;
				add(s.top(),-1);
				s.pop();
			}
			else
			{
				scanf("%d",&t);
				if(d[t]) printf("0\n");
				else 
				{
					int v=sum(t);
					printf("%d\n",bs(t,n+1,v+1)-bs(0,t,v)-1);
				}
			}
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值