题意:
q次操作,操作有三种:
(1,x)在可重集S中插入一个x
(2,x)从可重集S中删除一个x,保证删除合法
(3,x)问能否从可重集S中找到两个数a,b,满足a,b,x可以构成三角形
数据范围:q<=2e5,1<=x<=1e9
解法:
题解:
询问的时候只有三种情况:
1.(a,b,x),这种情况那么找两个x前面最大的,判断一下就行了
2.(a,x,b)
3,(x,a,b)
1的情况我用了线段树找前驱
2和3的情况,其实就是要找到一组(a,b),满足b>=x且b-a<x,
只考虑相邻的a和b,可以再开一棵线段树,存每个点与前驱的差值,再维护差值的最小值。
但是如果存在a>=b且a==b,这种情况也可以(上面维护前驱差值的时候不考虑相同的数)
这种情况需要再维护一下每个数是否出现超过两次。
因为数据范围比较大,操作比较少,所以用动态开点搞。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=6e5+5;
const int n=1e9+100;
int lc[maxm*40],rc[maxm*40];
int cnt[maxm*40],flag[maxm*40],midif[maxm*40];
int mi[maxm*40],ma[maxm*40];
int tot,rt1,rt2;
void pushup_cnt(int k){
cnt[k]=0;
flag[k]=0;
mi[k]=2e9;
ma[k]=0;
if(lc[k]){
cnt[k]+=cnt[lc[k]];
flag[k]|=flag[lc[k]];
mi[k]=min(mi[k],mi[lc[k]]);
ma[k]=max(ma[k],ma[lc[k]]);
}
if(rc[k]){
cnt[k]+=cnt[rc[k]];
flag[k]|=flag[rc[k]];
mi[k]=min(mi[k],mi[rc[k]]);
ma[k]=max(ma[k],ma[rc[k]]);
}
}
void pushup_dif(int k){
midif[k]=2e9;
if(lc[k])midif[k]=min(midif[k],midif[lc[k]]);
if(rc[k])midif[k]=min(midif[k],midif[rc[k]]);
}
void update_cnt(int x,int val,int l,int r,int& k){
if(!k)k=++tot;
if(l==r){
cnt[k]+=val;
flag[k]=(cnt[k]>=2);
mi[k]=(cnt[k]?l:2e9);
ma[k]=(cnt[k]?l:0);
return ;
}
int mid=(l+r)/2;
if(x<=mid)update_cnt(x,val,l,mid,lc[k]);
else update_cnt(x,val,mid+1,r,rc[k]);
pushup_cnt(k);
}
void update_dif(int x,int val,int l,int r,int& k){
if(!k)k=++tot;
if(l==r){
midif[k]=val;
return ;
}
int mid=(l+r)/2;
if(x<=mid)update_dif(x,val,l,mid,lc[k]);
else update_dif(x,val,mid+1,r,rc[k]);
pushup_dif(k);
}
int askma(int st,int ed,int l,int r,int k){
if(!k||!cnt[k])return 0;
if(st<=l&&ed>=r)return ma[k];
int mid=(l+r)/2;
int ans=0;
if(st<=mid)ans=max(ans,askma(st,ed,l,mid,lc[k]));
if(ed>mid)ans=max(ans,askma(st,ed,mid+1,r,rc[k]));
return ans;
}
int askmi(int st,int ed,int l,int r,int k){
if(!k||!cnt[k])return 2e9;
if(st<=l&&ed>=r)return mi[k];
int mid=(l+r)/2;
int ans=2e9;
if(st<=mid)ans=min(ans,askmi(st,ed,l,mid,lc[k]));
if(ed>mid)ans=min(ans,askmi(st,ed,mid+1,r,rc[k]));
return ans;
}
int askflag(int st,int ed,int l,int r,int k){
if(!k||!flag[k])return 0;
if(st<=l&&ed>=r)return flag[k];
int mid=(l+r)/2;
int ans=0;
if(st<=mid)ans|=askflag(st,ed,l,mid,lc[k]);
if(ed>mid)ans|=askflag(st,ed,mid+1,r,rc[k]);
return ans;
}
int askmidif(int st,int ed,int l,int r,int k){
if(!k||midif[k]==2e9)return 2e9;
if(st<=l&&ed>=r)return midif[k];
int mid=(l+r)/2;
int ans=2e9;
if(st<=mid)ans=min(ans,askmidif(st,ed,l,mid,lc[k]));
if(ed>mid)ans=min(ans,askmidif(st,ed,mid+1,r,rc[k]));
return ans;
}
//
void add(int x){
if(askma(x,x,0,n,rt1)==x){
update_cnt(x,1,0,n,rt1);
return ;
}
int ma1=askma(0,x-1,0,n,rt1);
int mi1=askmi(x+1,n,0,n,rt1);
update_cnt(x,1,0,n,rt1);
update_dif(mi1,mi1-x,0,n,rt2);
update_dif(x,x-ma1,0,n,rt2);
}
void del(int x){
update_cnt(x,-1,0,n,rt1);
if(askma(x,x,0,n,rt1)==x)return ;
int ma1=askma(0,x-1,0,n,rt1);
int mi1=askmi(x+1,n,0,n,rt1);
update_dif(mi1,mi1-ma1,0,n,rt2);
update_dif(x,2e9,0,n,rt2);
}
//
int check1(int x){
int b=askma(0,x,0,n,rt1);
if(!b)return 0;
update_cnt(b,-1,0,n,rt1);
int a=askma(0,x,0,n,rt1);
update_cnt(b,1,0,n,rt1);
if(!a)return 0;
return a+b>x;
}
int check2(int x){
int f=askflag(x,1e9,0,n,rt1);
if(f)return 1;
int dif=askmidif(x,1e9,0,n,rt2);
return dif<x;
}
//
signed main(){
//init
update_cnt(0,1e9,0,n,rt1);
update_cnt(n,1e9,0,n,rt1);
//
int q;scanf("%d",&q);
while(q--){
int op,x;scanf("%d%d",&op,&x);
if(op==1){
add(x);
}else if(op==2){
del(x);
}else if(op==3){
int ok=(check1(x)||check2(x));
if(ok)puts("Yes");
else puts("No");
}
}
return 0;
}