操作:
D:单点修改;
Q:查询该点所在的最大连续区间长度;
R:把最近一次删除的点还原;
我一开始的思路是:对于最长连续区间长度的查询,用的是set来存储之前被删除的点(目的是让点排好序),用数组模拟一下栈按删除顺序存点,对于当前要查找的点,利用二分查找找到set中第一个大于等于该位置的点,和前一个点作差,直接求出。
#include <bits/stdc++.h>
using namespace std;
const int N=5e4+5;
int a[N];
set<int>st;
int n,m,cnt;
int main()
{
int p;
set<int>::iterator it;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(a,0,sizeof(a));
st.clear();
cnt=0;
char ss[10];
for(int i=1;i<=m;i++)
{
scanf("%s",ss);
if(ss[0]=='D')
{
scanf("%d",&p);
st.insert(p);
a[++cnt]=p;
}
else if(ss[0]=='Q')
{
scanf("%d",&p);
if(st.empty())
printf("%d\n",n);
else
{
int ans=0;
it=st.lower_bound(p);//cout<<"it="<<*it<<endl;
if(it==st.end())
ans=n-*st.rbegin();
if(*it!=p&&it!=st.end())
{
int t=*it;
if(it!=st.begin())
{
it--;
ans=t-*it-1;
}
else
ans=*it-1;
}
printf("%d\n",ans);
}
}
else if(ss[0]=='R')
{
if(cnt>0)
{
p=a[cnt--];//cout<<"p="<<p<<endl;
st.erase(p);
}
}
}
}
return 0;
}
然后是用线段树的做法:
难点在于区间的合并,要用线段树来维护三个变量,一个是每个区间的最长连续长度,二是区间最左端的最长长度,三是区间最右端的最长长度。
区间合并时:
区间的最长长度=max{左右区间各自的最长长度,合并后中间可能产生的新的长度}
区间最左端的最长连续长度=
左边区间的最左端长度+(左边区间的最左端长度==左边区间长度?右边区间的最左端长度:0)
区间的最右端的最长连续长度同理。
然后是查询,具体见代码。
#include <bits/stdc++.h>
using namespace std;
const int N=5e4+5;
struct node
{
int left,len,right;
}tree[N<<2];
int a[N];
int n,m;
void pushup(int l,int r,int rt)//重点
{
int mid=(l+r)>>1;
tree[rt].len=max(max(tree[rt<<1].len,tree[rt<<1|1].len),tree[rt<<1].right+tree[rt<<1|1].left);
if(tree[rt<<1].left==mid-l+1)
tree[rt].left=tree[rt<<1].left+tree[rt<<1|1].left;
else
tree[rt].left=tree[rt<<1].left;
if(tree[rt<<1|1].right==r-mid)
tree[rt].right=tree[rt<<1].right+tree[rt<<1|1].right;
else
tree[rt].right=tree[rt<<1|1].right;
}
void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt].left=1;
tree[rt].right=1;
tree[rt].len=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(l,r,rt);
}
void update(int l,int r,int pos,int val,int rt)
{
if(l==r)
{
tree[rt].len=val;
tree[rt].left=val;
tree[rt].right=val;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)
update(l,mid,pos,val,rt<<1);
else
update(mid+1,r,pos,val,rt<<1|1);
pushup(l,r,rt);
}
int query(int l,int r,int pos,int rt)
{
if(tree[rt].len==r-l+1||tree[rt].len==0)
return tree[rt].len;
int mid=(l+r)>>1;
if(pos<=mid)//查询方法
return pos>mid-tree[rt<<1].right?tree[rt<<1].right+tree[rt<<1|1].left:query(l,mid,pos,rt<<1);
else
return pos<=mid+tree[rt<<1|1].left?tree[rt<<1].right+tree[rt<<1|1].left:query(mid+1,r,pos,rt<<1|1);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int cnt=0,p;
build(1,n,1);
char ss[5]={0};
for(int i=1;i<=m;i++)
{
scanf("%s",ss);
if(ss[0]=='D')
{
scanf("%d",&p);
a[++cnt]=p;
update(1,n,p,0,1);
}
else if(ss[0]=='Q')
{
scanf("%d",&p);//cout<<"p = "<<p<<endl;
printf("%d\n",query(1,n,p,1));
}
else if(ss[0]=='R')
{
if(cnt>0)
update(1,n,a[cnt--],1,1);
}
}
}
return 0;
}