题意:
有一串1,现在 D i 表示将第i个位置的点修改成0,R表示把最晚修改的一个数恢复成0,Q i表示询问包含第i个数在内的最长1串的长度
思路:
网上的代码大多用线段树维护连续区间的左右端点,本蒟篛并不是很理解。
我的方法是,两次二分,分别把第i个数的左部分最长1串的长度和第i个数右部分最长1串的长度求出,
其中二分的判断方式是区间和是否为区间长度,区间和用树状数组维护。
特别注意的是:一个已经被摧毁的村庄可能会再次被摧毁!
AC代码如下(二分代码极丑,希望谅解)
/*
最怕一生碌碌无为,还说平凡难能可贵。
*/
#include<bits/stdc++.h>
#define INF 50010
using namespace std;
int n,m;
int e[INF],cnt,pos,a[INF];
int lowbit(int x){return x&(-x);}
void add(int x,int y)
{
while(x<=n+1)
{
e[x]+=y;
x+=lowbit(x);
}
}
int getsum(int x)
{
int sum=0;
while(x>0)
{
sum+=e[x];
x-=lowbit(x);
}
return sum;
}
int getmaxlen(int x)
{
if(a[x]!=1)return 0;
int leftpos,rightpos;
int left=1,right=x,mid;
while(left<right)
{
mid=left+right>>1;
if(getsum(x)-getsum(mid-1)<x-mid+1)
left=mid+1;
else right=mid;
}
leftpos=left;
left=x,right=n+1;
while(left<right)
{
mid=left+right>>1;
if(getsum(mid)-getsum(x-1)<mid-x+1)
right=mid;
else left=mid+1;
}
rightpos=left;
return rightpos-leftpos;
}
int main()
{
//freopen("in.in","r",stdin);
ios::sync_with_stdio(false);cin.tie(NULL);
char s[2];
while(cin>>n>>m)
{
memset(e,0,sizeof(e));
stack<int>q;
for(int i=1;i<=n;i++)
add(i,1),a[i]=1;
cnt=pos=0;
while(m--)
{
cin>>s;
if(s[0]=='D')
{
cin>>pos;
q.push(pos);
if(a[pos]==1)
{
a[pos]=0;
add(pos,-1);
}
}
if(s[0]=='R')
{
if(!q.empty())
{
pos=q.top();
q.pop();
if(a[pos]==0)
{
a[pos]=1;
add(pos,1);
}
}
}
if(s[0]=='Q')
{
cin>>pos;
cout<<getmaxlen(pos)<<endl;
}
}
}
}