题目链接:https://ac.nowcoder.com/acm/contest/5667/H
害,由于网上的思路没有相同的..
自己写就debug了一天..
题目大意:
给你一个Multiset,支持三种操作:
1.集合中加入一个数x
2.集合中删除一个数x
3.询问集合中是否能选择两条边与x构成三角形
题目思路:
考虑题目里面有Multiset,那么就用一下Multiset。
对于一个满足要求的三角形来说,我们得知要满足 :a+b>c 或者 a-b<c
首先考虑对于询问的一个x来说
考虑三种情况:
(1) 作为最大边,此时需要求一下小于它的最大的两条边
(2) 作为中间边,此时需要求下小于它的,大于它的最小的
(3) 作为最小边,此时需要求一下大于它的两边的最小差值 | a-b<c
所以考虑第一种情况与第二种情况统统用Multiset实现
第三种情况维护最小差值,如果在线处理的话可能需要平衡树?(暂时鸽这,待补)
但是既然是询问,不妨离线处理一下
因为离线处理,那么就知道了所有询问点(有用点)
依次建线段树维护最小差值,查询大于x的最小差值也就是查询[getid(x),nn]的最小差值
依次将询问的x的通过以上三种情况考虑
便可以得出结论
第二种第三种情况(有注释)及线段树维护最小差值详见代码
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC option("arch=native","tune=native","no-zero-upper")
#pragma GCC target("avx2")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int Maxn=2e7+10;
const int maxn =2e5+10;
const int mod=998244353;
const int Mod = 1e9+7;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
struct Query{
int op,x;
}q[maxn];
vector<int>v;
struct node{
ll maxl,minl;
ll mi,val;
node(){maxl = -INF;minl = mi = INF;val = 0;}
}t[maxn*4];
multiset<ll>s;
void push(int k){
t[k].maxl = max(t[k<<1].maxl,t[k<<1|1].maxl);
t[k].minl = min(t[k<<1].minl,t[k<<1|1].minl);
t[k].mi = min(t[k<<1].mi,t[k<<1|1].mi);
t[k].mi = min(t[k].mi,t[k<<1|1].minl-t[k<<1].maxl);
}
void Insert(int k,int l,int r,int pos,int w){
if(l == r){
t[k].val += w;
t[k].maxl = -INF;
t[k].mi = t[k].minl = INF;
if(t[k].val){
t[k].maxl = t[k].minl = v[l-1];
if(t[k].val >= 2) t[k].mi = 0;
}
return;
}
int mid = (l+r)/2;
if(pos<=mid) Insert(k<<1,l,mid,pos,w);
else Insert(k<<1|1,mid+1,r,pos,w);
push(k);
}
void query_mi(int k,int l,int r,int x,int y,ll &ans,ll &pre){
if(x<=l&&y>=r){
ans = min(ans,t[k].mi);
ans = min(ans,t[k].minl-pre);
pre = t[k].maxl;
return ;
}
int mid = (l+r)/2;
if(x<=mid) query_mi(k<<1,l,mid,x,y,ans,pre);
if(y>mid) query_mi(k<<1|1,mid+1,r,x,y,ans,pre);
}
int query_val(int k,int l,int r,int pos){
if(l == r) return t[k].val;
int mid = (l+r)/2;
if(pos<=mid) return query_val(k<<1,l,mid,pos);
return query_val(k<<1|1,mid+1,r,pos);
}
int nn;
int getid(ll x){
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int check(int i){
int x,y;
int id = getid(q[i].x);
int cot = query_val(1,1,nn,id);
auto temp = s.lower_bound(q[i].x);
if(cot>=2) return 1;///等边三角形
///作为最大边
if(temp != s.begin()){
if(cot == 1) return 1;
else{
x = *prev(temp);
if(prev(temp)!=s.begin()){
y = *prev(prev(temp));
if(x+y>q[i].x) return 1;
}
}
}
///作为中间边
if(cot == 1){
if(temp != s.begin()) return 1;
auto tempx = s.upper_bound(q[i].x);
if(tempx != s.end() && (*tempx)<2ll*q[i].x) return 1;
}
else if(temp != s.end()&& temp != s.begin()){
x = *prev(temp),y = *temp;
if(x+q[i].x>y) return 1;
}
///作为最小边
ll pre = -INF,ans = INF;
query_mi(1,1,nn,id,nn,ans,pre);
if(ans<q[i].x) return 1;
return 0;
}
int main(){
/* s.insert(3);s.insert(3);s.insert(2);s.erase(3,1);
for(int x:s){
debug(x);
}*/
read(n);
for(int i=1;i<=n;i++){
scanf("%d%d",&q[i].op,&q[i].x);
v.push_back(q[i].x);
}
sort(v.begin(),v.end());
v.erase((unique(v.begin(),v.end())),v.end());
nn = v.size();
///debug(nn);
for(int i=1;i<=n;i++){
int f = 0;
int id = getid(q[i].x);
if(q[i].op == 1) Insert(1,1,nn,id,1),s.insert(q[i].x);
else if(q[i].op == 2){
Insert(1,1,nn,id,-1);
auto temp = s.lower_bound(q[i].x);
if(*temp == q[i].x) s.erase(temp);
}
else if(q[i].op == 3){
if(check(i)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
/**
**/