2020牛客暑期多校训练营(第二场)H(线段树+模拟)

H.Happy Triangle
思路:考虑构成三角形的充要条件是:任意两边之和大于第三边。
我们分三种情况进行讨论:
1.x是最大边
2.x是第二大边
3.x是第三大边

显然1,2两种情况可以用multiset来模拟讨论讨论。
我们用线段树来实现第三种情况的讨论,具体细节:
先将所有值存下来先离散化一下。
我们知道如果存在>=x且出现至少两次的y,则必然有解。可以用一个bit来解决这类情况。
否则,我们只需要在第一次添加和最后一次删除一个y的时候在线段树上更新大小相邻的两个点的差值。添加和删除都是最多影响两个位置的值,在multiset上二分找一下相邻的值即可。
具体实现见代码:
有问题可以私信博主QAQ

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;
int n,c[N],s[N],t[N];
multiset<int>G;
int gao1(int x){
  auto y=G.upper_bound(x);
  if(y==G.begin())return 0;
  y--;
  int dx=*y;
  if(y==G.begin())return 0;
  y--;
  return c[dx]+c[*y] >c[x];
}
int cnt[N];
int gao2(int x){
  if(cnt[x]>=2)return 1;
  if(cnt[x]==1){
    auto y=G.upper_bound(x);
    if(y!=G.end() && 2*c[x] >c[*y])return 1;
    y=G.lower_bound(x);
    if(y!=G.begin())return 1 ;
    return 0;
  }
  auto y=G.upper_bound(x);
  if(y==G.end())return 0;
  int dx=*y;
  y=G.lower_bound(x);
  if(y==G.begin())return 0;
  y--;
  return c[dx]<c[x]+c[*y];
}
int bt[N];
void add(int x,int y){
  for(;x<N;x+=x&-x)bt[x]+=y;
}
int get(int x){
  int y=0;
  for(;x;x-=x&-x)y+=bt[x];
  return y;
}
int tr[N<<2];
#define mid (l+r>>1)
#define ls o<<1
#define rs o<<1|1
void build(int o,int l,int r){
  tr[o]=2e9;
  if(l==r){
    return;
  }
  build(ls,l,mid);
  build(rs,mid+1,r);
}
void up(int o,int l,int r,int x,int y){
  if(l==r){
    tr[o]=y;
    return ;
  }
  if(x<=mid)up(ls,l,mid,x,y);
  else up(rs,mid+1,r,x,y);
  tr[o]=min(tr[ls],tr[rs]);
}
int get(int o,int l,int r,int x,int y){
  if(l>=x&&r<=y){
    return tr[o];
  }
  int ans=1e9;
  if(x<=mid)ans=min(ans,get(ls,l,mid,x,y));
  if(y>mid)ans=min(ans,get(rs,mid+1,r,x,y));
  return ans;
}
int len;
int gao3(int x){
  if(get(N-1)-get(x-1))return 1;
  if(c[x]>get(1,1,len,x,len))return 1;
  return 0;
}
int main() {
  ios::sync_with_stdio(false);
  cin>>n;
  for(int i=1;i<=n;i++){
    cin>>s[i]>>t[i];
    c[i]=t[i];
  }
  sort(c+1,c+1+n);
  len=unique(c+1,c+1+n)-c-1;
  for(int i=1;i<=n;i++)t[i]=lower_bound(c+1,c+1+len,t[i])-c;
  build(1,1,len);
  for(int i=1;i<=n;i++){
    if(s[i]==1) {
      G.insert(t[i]), cnt[t[i]]++;
      if(cnt[t[i]]==1){
        auto y=G.upper_bound(t[i]);
        if(y!=G.end()){
          assert(c[*y]>c[t[i]]);
          up(1,1,len,t[i],c[*y]-c[t[i]]);
        }else{
          up(1,1,len,t[i],2e9);
        }
        y--;
        if(y!=G.begin()){
          y--;
          assert(*y<t[i]);
          up(1,1,len,*y,c[t[i]]-c[*y]);
        }
      }
      if(cnt[t[i]]==2)add(t[i],1);
    }
    else if(s[i]==2) {
      G.erase(G.find(t[i])), cnt[t[i]]--;
      if(cnt[t[i]]==0){
        up(1,1,len,t[i],2e9);
        auto y=G.lower_bound(t[i]);
        int dx=*y;
        int sta=0;
        if(y==G.end())sta=1;
        if(y!=G.begin()){
          y--;
          assert(sta||dx>*y);
          up(1,1,len,*y,sta?2e9:(c[dx]-c[*y]));
        }
      }
      if(cnt[t[i]]==1)add(t[i],-1);
    } else{
      int st=gao1(t[i])||gao2(t[i])||gao3(t[i]);
      if(st)cout<<"Yes\n";
      else cout<<"No\n";
    }
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40655981/article/details/107345058