Tunnel Warfare
题目链接:https://vjudge.net/problem/POJ-2892
题意:有几个村庄,D a表示a村庄被摧毁,R表示修复上一个村庄,Q a表示包含a的连续村庄有多少个,如果a被摧毁则输出0。
思路:利用树状数组可以很好实现D和R的操作,,但是Q要怎么query呢?要log的查询,怎么二分呢?当然具有单调性啦,因为是连续的村庄,所以一直范围内递增啊。所以我们可以二分左右区间,或者直接二分。
建议在杭电交哦,poj数据…
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int lowbit(int c)
{
return c&(-c);
}
int c[53000],num[53000];
bool vis[53000];
int n,m,x,id=0,l,r;
char op[2];
int query(int x)
{
int cnt=0;
while(x)
{
cnt+=c[x];
x-=lowbit(x);
}
return cnt;
}
void add(int x,int val)
{
while(x<=n)
{
c[x]+=val;
x+=lowbit(x);
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(c,0,sizeof c);
memset(vis,1,sizeof vis);///vis[i]=1表示未被摧毁
for(int i=1; i<=n; i++)
{
add(i,1);
}
while(m--)
{
scanf("%s",op);
if(op[0]=='D')
{
scanf("%d",&x);
num[++id]=x;
if(vis[x])
{
vis[x]=0;
add(x,-1);
}
}
else if(op[0]=='R')
{
if(id>=1)
{
add(num[id],1);
vis[num[id]]=1;
id--;
}
}
else
{
scanf("%d",&x);
if(!vis[x])
printf("0\n");
else
{
int l=0,r=x,sum=query(x),ans2=n,ans1=1;///二分左区间
while(l<=r)
{
int mid=(l+r)/2;
if(sum-query(mid)==x-mid)
{
r=mid-1;
ans1=mid+1;
}
else
l=mid+1;
}
l=x,r=n;//二分右区间
while(l<=r)
{
int mid=(l+r)/2;
if(query(mid)-sum==mid-x)
{
l=mid+1;
ans2=mid;
}
else
r=mid-1;
}
//cout<<ans1<<"**"<<ans2<<endl;
cout<<ans2-ans1+1<<endl;
}
}
}
}
}
STL 每次把断点插入set里面,查找的时候二分查找就行了,修复后记得从set里面删除
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<stack>
using namespace std;
char op[2];
set<int> s;
set<int> ::iterator it;
stack<int> q;
int x;
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
s.clear();
while(!q.empty())q.pop();
while(m--)
{
scanf("%s",op);
if(op[0]=='D')
{
scanf("%d",&x);
s.insert(x);
q.push(x);
}
else if(op[0]=='Q')
{
scanf("%d",&x);
if(s.find(x)!=s.end())
printf("0\n");
else
{
int l=1,r=n;
it=s.lower_bound(x);
if(it!=s.end())
r=(*it-1);
if(it!=s.begin())
{
it--;
l=(*it)+1;
}
cout<<r-l+1<<endl;
}
}
else
{
if(!q.empty())
{
int a=q.top();
q.pop();
s.erase(a);
}
}
}
}
}