分析
一看跟区间有关,线段树应该可以做,但是不想写线段树,于是考虑树状数组行不行。因为这个前面后面都要考虑,所以就用两个树状数组。
在一次摧毁之后,直接通过更新这个位置到以后的贡献,前缀和之后后面的全都会改变,修复时同理,记录摧毁顺序用个stack就可以。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
int n,m,qq;
int c1[100010],c2[100010];
int v[50010];
int lowbit(int x)
{
return x&(-x);
}
void updatel(int x,int v)
{
for(int i=x;i<=n;i+=lowbit(i)) c1[i]+=v;
}
void updater(int x,int v)
{
for(int i=x;i>=1;i-=lowbit(i)) c2[i]+=v;
}
int queryl(int x)
{
int s=0;
for(int i=x;i>=1;i-=lowbit(i)) s+=c1[i];
return s;
}
int queryr(int x)
{
int s=0;
for(int i=x;i<=n;i+=lowbit(i)) s+=c2[i];
return s;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
{
updatel(i,1);
updater(i,1);
}
stack<int> st;
for(int i=1;i<=m;i++)
{
char op;
cin>>op;
if(op=='D')
{
int x;
cin>>x;
if(!v[x])
{
v[x]=1;
int tl=queryl(x),tr=queryr(x);
int pos1=x+queryr(x),pos2=x-queryl(x);
updatel(x+1,-tl);
updatel(pos1+1,tl);
updater(x-1,-tr);
updater(pos2-1,tr);
}
st.push(x);
}
else if(op=='Q')
{
int x;
cin>>x;
if(v[x]) cout<<0<<endl;
else cout<<queryl(x)+queryr(x)-1<<endl;
}
else
{
if(v[st.top()]&&!st.empty())
{
v[st.top()]=0;
int x=st.top();
st.pop();
int tl=queryl(x),tr=queryr(x);
int pos1=x+queryr(x),pos2=x-queryl(x);
updatel(x+1,tl);
updatel(pos1+1,-tl);
updater(x-1,tr);
updater(pos2-1,-tr);
}
}
}
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
memset(v,0,sizeof(v));
}
return 0;
}