题目还是不错的 需要仔细分析一下
题意:
给一个可重复集合,最初为空。每次操作为 op,x
如果op==1,向集合中插入x
如果op==2,删除集合中的x(保证x一定在集合中)
如果op==3,询问集合中是否存在两个数a,b使得a,b,x可以构成三角形
我们分析一下a,b,x的关系
如果 a<b<=x 根据三角形的构成条件 必须满足 a+b>x
如果 a<=x<=b 则必须满足 a+x>b 那么肯定是 a是x前驱 b是x的后继的时候最好
如果 x<a<b 这个就是本题的精髓了 其实也不是特别难 x+a>b 但是我们不好维护x+a 我们可以维护 b-a 而要使得b-a最小 我们 那肯定是 a是b的前驱的时候最小
所以在平衡树中 我们需要维护 一个点自身的权值 以及它和前驱的差值 第三个操作 在大于a的树中获得最小前驱差值就行了
好久没写平衡树了 感觉还是 fhq好写一点 当时为了学lct 去搞splay了 但是lct的splay还是有些不一样 单写平衡树 还是fhq好些一点?
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+100;
const int inf = 1e9;
#define lc(x) c[x][0]
#define rc(x) c[x][1]
int root,cnt;
int c[N][2],siz[N],det[N],L[N],R[N],val[N],pri[N];
void pushup(int x){
siz[x]=siz[lc(x)]+siz[rc(x)]+1;
det[x]=min(det[lc(x)],det[rc(x)]);
L[x]=val[x];R[x]=val[x];
if(lc(x)){
det[x]=min(det[x],val[x]-R[lc(x)]);
L[x]=L[lc(x)];
}
if(rc(x)){
det[x]=min(det[x],L[rc(x)]-val[x]);
R[x]=R[rc(x)];
}
}
void split(int now,int k,int &x,int &y){
if(!now){
x=y=0;
}else{
if(val[now]<=k) x=now,split(rc(now),k,rc(now),y);
else y=now,split(lc(now),k,x,lc(now));
pushup(now);
}
}
int merge(int x,int y){
if(x==0||y==0) return x+y;
if(pri[x]<pri[y]){
rc(x)=merge(rc(x),y);
pushup(x);return x;
}else{
lc(y)=merge(x,lc(y));
pushup(y);return y;
}
}
int new_node(int x){
cnt++;
val[cnt]=L[cnt]=R[cnt]=x;det[cnt]=inf;siz[cnt]=1;
pri[cnt]=rand();
return cnt;
}
int kth(int x,int k){
while(x){
if(k<=siz[lc(x)]) x=lc(x);
else if(k>siz[lc(x)]+1) k-=siz[lc(x)]+1,x=rc(x);
else return val[x];
}
}
int main(){
srand(time(NULL));
int q;
scanf("%d",&q);
det[0]=inf;
while(q--){
int op,v,x,y,z;
scanf("%d%d",&op,&v);
if(op==1){
split(root,v,x,y);
root=merge(merge(x,new_node(v)),y);
}else if(op==2){
split(root,v,x,z);
split(x,v-1,x,y);
y=merge(lc(y),rc(y));
root=merge(merge(x,y),z);
}else{
split(root,v,x,z);
split(x,v,x,y);
int flag=0;
if(siz[x]>=2){
if(kth(x,siz[x])+kth(x,siz[x]-1)>v)flag=1;
}
if(x&&z){
if(kth(x,siz[x])+v>kth(z,1))flag=1;
}
if(siz[z]>=2){
if(det[z]<v)flag=1;
}
root=merge(merge(x,y),z);
if(flag)printf("Yes\n");
else printf("No\n");
}
}
return 0;
}