县城里有 \(n\) 个用地道相连的房子,初始时全部房屋未被摧毁,第 \(i\) 个只与第 \(i-1\) 和第 \(i+1\) 个相连。这时有 \(m\) 个消息依次传来:
若消息为 D x
:鬼子将 \(x\) 号房子摧毁了,地道被堵上。
若消息为 R
:村民们将鬼子上一个摧毁的房子修复了。
若消息为 Q x
:有一名士兵被围堵在 \(x\) 号房子中。
李云龙收到信息很紧张,他想知道每一个被围堵的士兵通过地道能够到达的房子有几个。请注意,如果士兵所在的房子已被摧毁,那么他无法行动。
\(1\leq n,m\leq 5\times 10^4\)。
这道题我先想到了一个 std::set
做法,但是不想写二分,于是想到了一个正经的平衡树做法。
首先,我们用一个栈和一个平衡树来维护被摧毁的元素,然后用一个状态数组维护房屋是否被摧毁。
注意,可能当前没有房屋被破坏,直接询问会出锅,我们可以插入虚拟节点 \(0,n+1\),由于它们不存在,把它们看成摧毁了的房屋是可以的。
平衡树这里使用的我最近学习的 \(\textbf{FHQ Treap}\)。
时间复杂度 \(O(m\log n)\)。
#include <bits/stdc++.h> #define int long long using namespace std; namespace FHQTreap{ const int SIZE = 5e4+5; int son[SIZE][2]; int val[SIZE],rk[SIZE],siz[SIZE],root,points; mt19937 randomer(time(0)); #define ls(i) (son[(i)][0]) #define rs(i) (son[(i)][1]) void pushup(int i){ siz[i]=siz[ls(i)]+siz[rs(i)]+1; } int newnode(int v){ val[++points]=v; rk[points]=randomer(); siz[points]=1; return points; } void split(int p,int v,int &left,int &right){ if(!p){ left=right=0; return; } if(val[p]<=v){ left=p; split(rs(p),v,rs(left),right); } else{ right=p; split(ls(p),v,left,ls(right)); } pushup(p); } int merge(int left,int right){ if(!left||!right){ if(left)return left; else if(right)return right; else return 0; } if(rk[left]<rk[right]){ ls(right)=merge(left,ls(right)); pushup(right); return right; } else{ rs(left)=merge(rs(left),right); pushup(left); return left; } } void insert(int v){ int left=0,right=0; split(root,v-1,left,right); root=merge(merge(left,newnode(v)),right); } void remove(int v){ int left=0,mid=0,right=0; split(root,v,left,right); split(left,v-1,left,mid); mid=merge(ls(mid),rs(mid)); root=merge(merge(left,mid),right); } int pre(int v){ int now=root,ret=0; while(1){ if(!now){ return ret; } else if(v<=val[now]){ now=ls(now); } else{ ret=val[now]; now=rs(now); } } } int next(int v){ int now=root,ret=0; while(1){ if(!now){ return ret; } else if(v>=val[now]){ now=rs(now); } else{ ret=val[now]; now=ls(now); } } } } namespace solution{ int n,m; stack<int> destoried; bool status[50005]; int solution(){ cin>>n>>m; FHQTreap::insert(0); FHQTreap::insert(n+1); while(m--){ char op;int x; cin>>op; if(op=='D'){ cin>>x; destoried.push(x); FHQTreap::insert(x); status[x]=true; } else if(op=='R'){ FHQTreap::remove(destoried.top()); status[destoried.top()]=false; destoried.pop(); } else{ cin>>x; if(status[x]){ cout<<0<<'\n'; } else{ cout<<(FHQTreap::next(x)-FHQTreap::pre(x)-1)<<'\n'; } } } return 0; } } signed main(){ ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); return solution::solution(); }
AC Record