牛客多校2 Happy Triangle FHQ-treap 维护前驱差

题目还是不错的  需要仔细分析一下

题意:

给一个可重复集合,最初为空。每次操作为 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;
} 

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值