poj都给hint,D x摧毁x,R恢复最近摧毁的点,Q x查看和x相连的点的个数(未摧毁)。
做法:
1)训练计划上把这题分到静态二叉检索树上,所以先想到用线段树做,线段树维护每段中被消除点的最大位置和最小位置,摧毁点k就把k添加到位置k,查询k,就查询段[1,k]的中的最大值和[k,n]的最小值,然后相减得到结果。初始化时最大值为0,最小值为n+1,这样在区间如果没有被摧毁的点也能返回正确结果,有也能正确更新。查询和插入都是logn
2)第二种做法是把摧毁的点的位置都放到有序序列里,查询k时二分查找比k大的第一个数,和比k小的第一个数,如果k没被摧毁,相减就是结果。而这个有序序列用set就行了,插入和查询也都是logn,直接用set的里lower_bound,用algorithm里的lower_bound会超时(对于set,list这种不能随机访问的容器,algorithm
中的lower_bound可能变成了nlogn)。
线段树做法
#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<algorithm>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define maxn 55000
#define LL long long
using namespace std;
#define ls o*2,l,m
#define rs o*2+1,m+1,r
int MAX;
struct node
{
int l,r;
int mmax,mmin;
void set(int l,int r){ this->l=l,this->r=r,this->mmax=0,this->mmin=MAX;}
int getM(){ return (l+r)/2; }
}seg[maxn*3];
void build(int o,int l,int r)
{
seg[o].set(l,r);
int m=(l+r)/2;
if(l<r)
{
build(ls);
build(rs);
}
}
void update(int o,int pos,int v)
{
if(seg[o].l==seg[o].r)
{
if(v!=-1)
{
seg[o].mmax=v;
seg[o].mmin=v;
}
else
{
seg[o].mmax=0;
seg[o].mmin=MAX;
}
return;
}
int m=seg[o].getM();
if(pos<=m)
update(o*2,pos,v);
else
update(o*2+1,pos,v);
seg[o].mmax=max(seg[o*2].mmax,seg[o*2+1].mmax);
seg[o].mmin=min(seg[o*2].mmin,seg[o*2+1].mmin);
}
int queryMAX(int o,int ql,int qr)
{
if(ql>qr)
return -1;
if(ql<=seg[o].l && seg[o].r<=qr)
return seg[o].mmax;
int m=seg[o].getM();
int mmax=-1;
if(ql<=m)
mmax=max(mmax,queryMAX(o*2,ql,qr));
if(qr>m)
mmax=max(mmax,queryMAX(o*2+1,ql,qr));
return mmax;
}
int queryMIN(int o,int ql,int qr)
{
if(ql>qr)
return -1;
if(ql<=seg[o].l && seg[o].r<=qr)
return seg[o].mmin;
int m=seg[o].getM();
int mmin=INT_MAX;
if(ql<=m)
mmin=min(mmin,queryMIN(o*2,ql,qr));
if(qr>m)
mmin=min(mmin,queryMIN(o*2+1,ql,qr));
return mmin;
}
int main()
{
int n, m;
while(scanf("%d%d",&n,&m)!=EOF)
{
MAX=n+1;
build(1,0,n+1);
char op[10];
int pos;
stack<int>sta;
for(int i=0;i<m;++i)
{
scanf("%s",op);
if(op[0]=='D')
{
scanf("%d",&pos);
update(1,pos,pos);
sta.push(pos);
}
else if(op[0]=='R')
{
pos=sta.top();
sta.pop();
update(1,pos,-1);
}
else
{
scanf("%d",&pos);
int L=queryMAX(1,1,pos);
int R=queryMIN(1,pos,n);
printf("%d\n",max(0,R-L-1));
}
}
}
}
set二分
#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<algorithm>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define maxn 55000
#define LL long long
using namespace std;
set<int>_set;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
_set.clear();
stack<int>sta;
char op[10];int pos;
_set.insert(0),_set.insert(n+1);
for(int i=0;i<m;++i)
{
scanf("%s",op);
if(op[0]=='D')
{
scanf("%d",&pos);
_set.insert(pos);
sta.push(pos);
}
else if(op[0]=='R')
{
pos=sta.top();
sta.pop();
_set.erase(pos);
}
else
{
scanf("%d",&pos);
// set<int>::iterator iter=lower_bound(_set.begin(),_set.end(),pos);//超时,看来set里的lower_bound是优化过的,比较快
set<int>::iterator iter=_set.lower_bound(pos);
int R=*iter;
int L=*(--iter);
if(R==pos)
printf("0\n");
else
printf("%d\n",R-L-1);
}
}
}
}