标签:P1503 进村 val 鬼子 int FHQTreap 摧毁 now SIZE
题面
县城里有 \(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
做法,但是不想写二分,于是想到了一个正经的平衡树做法。
首先,我们用一个栈和一个平衡树来维护被摧毁的元素,然后用一个状态数组维护房屋是否被摧毁。
- 如果是一个摧毁操作,那么将 \(x\) 放入栈、平衡树中。然后标记。
- 如果是一个修复操作,那么将栈顶元素从平衡树中删除,并取消标记,然后出栈。
- 如果是要给询问操作,可见这就是在询问平衡树中 \(x\) 的前驱后继的距离(也就是到被破坏的距离)减 \(2\)(首尾被破坏)。直接在平衡树上处理即可。
注意,可能当前没有房屋被破坏,直接询问会出锅,我们可以插入虚拟节点 \(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();
}
标签:P1503,进村,val,鬼子,int,FHQTreap,摧毁,now,SIZE 来源: https://www.cnblogs.com/zheyuanxie/p/p1503.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。