poj 2892 Tunnel Warfare

链接:点击打开链接

 给你N个相连的村庄,有三种操作,D x是把x村庄销毁(就是这个村庄与其他村庄的路都毁掉),Q x是问你有几个村庄与之相连,R是把最近销毁的村庄复原。


求的是连续的区间,区间合并问题,村庄左连续和右连续的村庄,就可以得出总连续的村庄。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 50010
int treel[4*N];
int treer[4*N];
int mark[N];
void bulid(int l,int r,int n){
	treel[n]=treer[n]=r-l+1;//初始化左连续相连的长度和右连续相连的长度 
	if(l==r)
	return;
	int mid;
	mid=(l+r)>>1;
	bulid(l,mid,2*n);
	bulid(mid+1,r,2*n+1); 
	}
void update(int l,int r,int n,int a,int op){
	if(l==r&&l==a){
		 if(op==1){//摧毁 
			    treel[n]=0;
			    treer[n]=0;
				}
		 else{//修复 
				treel[n]=1;
				treer[n]=1; 
				}
			return;			
		}
	 int mid;
	 mid=(l+r)>>1;
	 if(a<=mid)
	 update(l,mid,2*n,a,op);
	 else 
	 update(mid+1,r,2*n+1,a,op);
	 treel[n]=treel[2*n];//更新 
	 treer[n]=treer[2*n+1];
	 if(treel[2*n]==mid-l+1)
	  treel[n]+=treel[2*n+1];	
	 if(treel[2*n+1]==r-mid)
	 treer[n]+=treer[2*n];  
	}
int query(int l,int r,int n,int a){
	if(treel[n]==r-l+1) //连续区间 
	return treel[n];
	if(l==r)
	return 0;
	int mid=(l+r)>>1;
	if(a<=mid){
		if(mid-treer[2*n]<a)//最右值减去最右值还小于a,说明就在在这个区间里,就不用往下搜啦 
		return treer[2*n]+treel[2*n+1];
		return query(l,mid,2*n,a);
		}
	 else{
			if(mid+1+treel[2*n+1]>a)//同理,最左值加最左值还大于a,说明就在这个区间,就不用往下搜啦 
			return treer[n*2]+treel[2*n+1];
			return query(mid+1,r,2*n+1,a); 
			}	
	 return -1;		
	}	
int main(){
	int n,m,ok,a;
	char c;
	while(~scanf("%d %d",&n,&m)){
		bulid(1,n,1);
		ok=0;
		while(m--){
			getchar();
			scanf("%c",&c);
			if(c!='R'){
				scanf("%d",&a);
				if(c=='Q')
				printf("%d\n",query(1,n,1,a));
				else{
					mark[ok]=a;
					ok++;
					update(1,n,1,a,1);
					}
				}
				else{
					ok--;
					update(1,n,1,mark[ok],2);
					}
			}
		}
		return 0;
	}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值