题意:3种操作
1、往多重集 插入一个x
2、从多重集合里 删除一个x
3、询问多重集和是否有两个值 a、b 使得 a、b、x构成一个合法的三角形。
官方题解:
做法:对所有的数按序排成一列,当查询一个x时 ,对于合法的a、b (ax(两边之和大于第三条边),且取a、b是相邻的时候是最 容易得到解,于是 对 x/2+1 二分找到b的位置,那么大于b的位置 后面的值均满足a+b>x的条件。
构成三角形的条件还有一条:任意两边之差小于第三边。b-a
这里线段树我用动态开点的做法维护
对于1、2 的操作 用map维护,至于维护3:插入一个新的x时,就得维护x在线段树有序 序列中 减去前一个位置的差,后一个位置 减去x的值。
说起来我都有点绕不开了。
总之两句句话,
1、线段树维护相邻数之间的差
2、新插入一个数 会影响两个位置的值,删除一个数也会影响两个位置的值1
#include
using namespace std;
const int N=1e6+10,MAX=1e9;
int mi[40*N], ls[40*N], rs[40*N], cnt, rt;
mapmp;
void update(int &id, int l, int r, int pos, int val)
{
if(id==0) id = ++cnt, mi[id] = val;
if(l == r){mi[id] = val;return ;}
int mid = l + r >> 1;
if(pos <= mid) update(ls[id], l, mid , pos, val);
else update(rs[id], mid + 1, r, pos, val);
int ans = 2e9;
if(ls[id]) ans = min(ans, mi[ls[id]]);
if(rs[id]) ans = min(ans, mi[rs[id]]);
mi[id] = ans;
}
int ask_min(int id,int l,int r,int ql,int qr)
{
if(r < l || !id) return 2e9;
if(ql <= l && r <= qr) return mi[id];
int ans = 2e9;
int mid = l + r >> 1;
if(ql <= mid) ans = min(ans, ask_min(ls[id], l, mid, ql, qr));
if(qr > mid) ans = min(ans, ask_min(rs[id], mid+1, r, ql, qr));
return ans;
}
void add(int x)
{
mp[x]++;
if(mp[x]==1){
auto it = mp.lower_bound(x);
++it;
if(it != mp.end() && it->second == 1){//后面一个数减去现在这个数
update(rt, 0, MAX, it->first, it->first - x);
}
--it;
int l = -2e9;
if(it != mp.begin()) l = (--it)->first;//现在这个数减去前面那个数
update(rt, 0, MAX, x, x - l);
}
else if(mp[x] == 2) update(rt, 0, MAX, x, 0);//有两个相同的了
}
void del(int x){
auto it=mp.lower_bound(x);
mp[x]--;
int l=-1e9;
if(it!=mp.begin()){
l=(--it)->first;
++it;
}
if(mp[x]==0){
if((++it)!=mp.end() && it->second==1)
update(rt,0,MAX,it->first,it->first-l);
update(rt,0,MAX,x,2e9);
mp.erase(x);
}
else if(mp[x]==1)update(rt,0,MAX,x,x-l);
}
int ask(int x)
{
auto it = mp.lower_bound(x/2+1);
if(it == mp.end()) return 2e9;
if(it->second > 1) return it->first;
if(it != mp.begin()){
auto l = it; --l;
if(l -> first + it -> first > x) return it->first;
}
if((++it) != mp.end()) return it->first;
return 2e9;
}
int main()
{
//freopen("input.txt","r",stdin);
int q;scanf("%d", &q);
while(q--){
int op, x;
scanf("%d%d", &op, &x);
if(op == 1) add(x);
if(op == 2) del(x);
if(op == 3) {
if(ask_min(1, 0, MAX, ask(x), 1e9) < x) puts("Yes");
else puts("No");
}
}
return 0;
}