其他与平常的区间合并无异处。
最大难度的地方就是query函数的写法。
见代码。代码注释。
附图理解。
#include <cstdio>
#include <stack>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int Max=50010;
int maxn[Max<<2],lmaxn[Max<<2],rmaxn[Max<<2],cov[Max<<2];
void pushup(int rt,int m)
{
lmaxn[rt]=lmaxn[rt<<1];
rmaxn[rt]=rmaxn[rt<<1|1];
if(lmaxn[rt]==m-(m>>1)) lmaxn[rt]+=lmaxn[rt<<1|1];
if(rmaxn[rt]==(m>>1)) rmaxn[rt]+=rmaxn[rt<<1];
maxn[rt]=max(max(maxn[rt<<1],maxn[rt<<1|1]),lmaxn[rt<<1|1]+rmaxn[rt<<1]);
}
void build(int l,int r,int rt)
{
maxn[rt]=lmaxn[rt]=rmaxn[rt]=r-l+1;
if(l==r)
return ;
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt,r-l+1);
}
void update(int c,int k,int l,int r,int rt)
{
if(l==r)
{
maxn[rt]=lmaxn[rt]=rmaxn[rt]=k;
return ;
}
int m=(l+r)>>1;
if(c<=m) update(c,k,lson);
else update(c,k,rson);
pushup(rt,r-l+1);
}
int query(int c,int l,int r,int rt)
{
if(l==r||maxn[rt]==r-l+1||maxn[rt]==0)
return maxn[rt];
int m=(l+r)>>1;
if(c<=m)
{
if(c>=m-rmaxn[rt<<1]+1) //如果点位于左子树的右连续区间上,则可能要和右子树的左连续区间合并。
return query(c,lson)+query(m+1,rson);
else //点位于左子树的左连续区间上。无需合并
return query(c,lson);
}
if(c>m)
{
if(c<=m+lmaxn[rt<<1|1]) //如果点位于右子树的左连续区间上,则可能需要和左子树的右连续区间合并。
return query(m,lson)+query(c,rson);
else //点位于右子树的右连续区间。无需合并。
return query(c,rson);
}
}
int main()
{
int n,m,a;
scanf("%d %d",&n,&m);
build(1,n,1);
char ch[2];
stack<int >k;
while(m--)
{
scanf("%s%d",ch,&a);
if(ch[0]=='D')
{
update(a,0,1,n,1);
k.push(a);
}
else if(ch[0]=='R')
{
int t=k.top();
update(t,1,1,n,1);
k.pop();
}
else if(ch[0]=='Q')
printf("%d\n",query(a,1,n,1));
}
return 0;
}
第一种情况 ,需要和右子树的左连续区间合并。
第二种,无需合并。
第三种,
需要和左子树的右连续区间合并。
第四种。。。。