题目链接:传送门
D,和R就是单点更新的。主要考虑Q怎么写,既然是包括该点,肯定是以它为中心的,然后向上回溯,找他的左右是不是和他连续的。
对于一个点,看它是在当前区间的左半还是右半
在左半的话,看看是不是在右端的连续区间内,是的话,还要加上右半区间的左端连续区间。否则的话,只要计算它在左半区间的连接情况即可
在右半的话同理,看看是不是在左端的连续区间内,是的话,还要加上左半区间的右端连续区间。否则的话,只要计算它在右半区间的连接情况即可
核心代码:int query(int p,int l,int r,int rt)
{
if(l==r||msum[rt]==0||msum[rt]==r-l+1)
return msum[rt];
int m=(l+r)>>1;
if(p<=m)
{
if(p>=m-rsum[rt<<1]+1)
return (query(p,lson)+query(m+1,rson));
else return query(p,lson);
}
else
{
if(p<=m+lsum[rt<<1|1]) return (query(m,lson)+query(p,rson));
else return query(p,rson);
}
}
整个代码:
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<stack>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn=2e5;
int msum[maxn<<2],lsum[maxn<<2],rsum[maxn<<2];
int cover[maxn<<2];
void Pushup(int rt,int len)
{
lsum[rt]=lsum[rt<<1];
rsum[rt]=rsum[rt<<1|1];
if(lsum[rt]==(len-(len>>1)))lsum[rt]+=lsum[rt<<1|1];
if(rsum[rt]==(len>>1))rsum[rt]+=rsum[rt<<1];
msum[rt]=max(msum[rt<<1],max(msum[rt<<1|1],rsum[rt<<1]+lsum[rt<<1|1]));
}
void build(int l,int r,int rt)
{
msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
cover[rt]=-1;
if(l==r)return;
int m=(l+r)>>1;
build(lson);
build(rson);
}
void updata(int p,int c,int l,int r,int rt)
{
if(l==r)
{
msum[rt]=lsum[rt]=rsum[rt]=c?1:0;
return;
}
int m=(l+r)>>1;
if(p<=m)updata(p,c,lson);
if(p>m)updata(p,c,rson);
Pushup(rt,r-l+1);
}
int query(int p,int l,int r,int rt)
{
if(l==r||msum[rt]==0||msum[rt]==r-l+1)
return msum[rt];
int m=(l+r)>>1;
if(p<=m)
{
if(p>=m-rsum[rt<<1]+1)
return (query(p,lson)+query(m+1,rson));
else return query(p,lson);
}
else
{
if(p<=m+lsum[rt<<1|1]) return (query(m,lson)+query(p,rson));
else return query(p,rson);
}
}
int main()
{
int t,k,n,a,b,c,i;
char op[2];
stack<int> q;
while(~scanf("%d %d",&n,&k)&&n)
{
build(1,n,1);
while(k--)
{
scanf("%s",op);
if(op[0]=='D')
{
scanf("%d",&a);
q.push(a);
updata(a,0,1,n,1);
}
if(op[0]=='R')
{
a=q.top();
q.pop();
updata(a,1,1,n,1);
}
if(op[0]=='Q')
{
scanf("%d",&a);
printf("%d\n",query(a,1,n,1));
}
}
}
return 0;
}