题意:
给你n个村庄,他们按照顺序连在一起,有3种操作。
D X,摧毁X,所以它两边的边也没了。
R,恢复最近一次摧毁的村庄
Q X,问你x村庄向左向右,一共连了多少个村庄。
题目没说清楚的地方:
(1)多case
(2)某个村庄可以被毁坏多次(必须全部入栈),但只需要一次就能将其恢复(下面的这组数据,,)
(3)D 3 D 2 D 1 D 1 D 2
//R 恢复2
//R 恢复1
//R 恢复3
1.用set做。把摧毁的村庄加入set,然后二分查找x,找到前一个和后一个,做差即可。为了方便可以把0和n+1放入set。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stack>
#include <set>
using namespace std;
#define LL long long
set<int> st;
stack<int> q;
set<int> ::iterator it;
int vis[100000];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
st.clear();
memset(vis,0,sizeof vis);
while(!q.empty()) q.pop();
st.insert(0);
st.insert(n+1);
for(int i=1;i<=m;i++){
char c;
cin>>c;
if(c=='D') {
int x;scanf("%d",&x);
q.push(x);
st.insert(x);
vis[x]=1;
}else if(c=='R'){
while(!q.empty()&&vis[q.top()]==0){
q.pop();
}
if(!q.empty()){
st.erase(st.lower_bound(q.top()));
vis[q.top()]=0;
q.pop();
}
}else{
int x;scanf("%d",&x);
it=st.lower_bound(x);
if(*it==x){
printf("0\n");
}else{
printf("%d\n",*it-*(--it)-1);
}
}
}
}
}
2.常规的线段树写。
每一个区间保存L,R。L代表左端点向右有几个连续的村庄。R同理。
难点在于查询。query(x)代表查询x村庄。
如果这个区间l==r或者整个区间都有村庄连续着(R[x]==r-l+1) 那么直接返回。
若x在左子树,那么看看左子树的R[lt]包不包含x,若包含:
就还要查询右子树即(query(mid+1)) 查询右子树的最左端点在【区间内】有多少连续的。
同理。x在右子树也一样。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stack>
using namespace std;
#define LL long long
#define lt x<<1
#define rt x<<1|1
const int maxn = 100000+33;
stack<int> q;
int L[maxn<<2],R[maxn<<2];
void update(int x,int l,int r)
{
L[x]=L[lt];
R[x]=R[rt];
int mid = (l+r)>>1;
if(L[lt]==mid-l+1) L[x]+=L[rt];
if(R[rt]==r-mid) R[x]+=R[lt];
}
void build(int x,int l,int r)
{
if(l==r){
L[x]=R[x]=1;
}else{
int mid = (l+r)>>1;
build(lt,l,mid);
build(rt,mid+1,r);
update(x,l,r);
}
}
void change(int x,int l,int r,int pos,int p)
{
if(l==r){
L[x]=R[x]=p;
}else{
int mid = (l+r)>>1;
if(pos<=mid) change(lt,l,mid,pos,p);
else change(rt,mid+1,r,pos,p);
update(x, l, r);
}
}
int query(int x,int l,int r,int pos)
{
if(l==r||r-l+1==R[x]){
return R[x];
}else{
int mid = (l+r)>>1;
if(pos<=mid){
if(pos>=mid-R[lt]+1){
return query(lt,l,mid,pos)+query(rt,mid+1,r,mid+1);
}else
return query(lt,l,mid,pos);
}else{
if(pos<=mid+L[rt])
return query(lt,l,mid,mid)+query(rt,mid+1,r,pos);
else
return query(rt,mid+1,r,pos);
}
}
}
int vis[100000];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
memset(vis,0,sizeof vis);
while(!q.empty()) q.pop();
build(1, 1, n);
for(int i=1;i<=m;i++){
char c;
cin>>c;
if(c=='D') {
int x;scanf("%d",&x);
q.push(x);
change(1,1,n,x,0);
vis[x]=1;
}else if(c=='R'){
while(!q.empty()&&vis[q.top()]==0){
q.pop();
}
if(!q.empty()){
change(1,1,n,q.top(),1);
vis[q.top()]=0;
q.pop();
}
}else{
int x;scanf("%d",&x);
printf("%d\n",query(1,1,n,x));
}
}
}
}