题目链接:
http://poj.org/problem?id=2892
题意:
【题意】
有n个村庄进行m次操作,有三种操作
D x:表示摧毁一个村庄
Q x:表示查询一个村庄左右连续的存在的村庄个数,若该村庄不存在为0
R:表示修复上一个被摧毁的村庄
【输入】
第一行n,m
接下来m行每行表示一个命令
【输出】
对于每次查询输出答案
题解:
每次二分查找从x向左的第一个被摧毁的村庄位置,两边二分,需要用树状数组或线段树维护区间和来快速判断二分。
代码:
#include<iostream>
#include<algorithm>
#include<string.h>
#include<stack>
#include<stdio.h>
#define maxn (50005)
using namespace std;
int n,m,num[maxn];
stack<int>s;
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int v)
{
for (int i=x;i<=n+1;i+=lowbit(i))
num[i]+=v;
return ;
}
int query(int x)
{
int ans=0;
for (int i=x;i>0;i-=lowbit(i))
ans+=num[i];
return ans;
}
int getsum(int x,int y)
{
return query(y)-query(x-1);
}
char p[5];
int erfen1(int l,int r)
{
int ans=1;
while(l<=r)
{
//cout<<l<<
int mid=(l+r)/2;
if (getsum(mid,r)==r-mid+1)
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
return ans;
}
int erfen2(int l,int r)
{
int ans=n;
while(l<=r)
{
//cout<<l<<' '<<r<<endl;
int mid=(l+r)/2;
if (getsum(l,mid)==mid-l+1)
{
ans=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
add(i,1);
for (int i=1;i<=m;i++)
{
int tmp;
scanf("%s",p);
if (p[0]=='R')
{
tmp=s.top();
s.pop();
add(tmp,1);
}
else
{
scanf("%d",&tmp);
if(p[0]=='D')
{
add(tmp,-1);
s.push(tmp);
continue;
}
if (getsum(tmp,tmp)==0)
{
printf("0\n");
continue;
}
int a1=erfen1(1,tmp);
int a2=erfen2(tmp,n);
//cout<<a1<<' '<<a2<<endl;
int ans=a2-a1+1;
printf("%d\n",ans);
}
}
}