2020牛客多校训练赛(第二场)补题

比赛入口 

 

H-Happy Triangle

题意:

  有一个multiset  s,一共有三种操作:

  1.  s插入一个x;

  2.  s删除一个x;

  3.  查询s中是否存在两个数字,使得这两个数字能和x组成一个非退化三角形;

 

思路:

  显然,s是有序的,且判断x是否能和s中两个数字组成非退化三角形,一共有以下三种情况:

  1. x是最大边,判断<=x的最后两个字;

  2. x是第二大边,判断>=x的第一个数字和<x的最后一个数字;

  3. x是最小边,判断比x大的任意两个数字的差值的绝对值小于x,由于s可视作有序,那么最优的方法就是从相邻的数字中找。

      这里可以用权值线段树来维护差值(下一个数字 - 当前数字),由于x∈[1,1e9] ,因此可以采取离线+离散化的做法。每次查询最小的差值即可。

  1 #include<bits/stdc++.h>
  2 /*
  3 #include<cstdio>
  4 #include<cmath>
  5 #include<cstring>
  6 #include<vector>
  7 #include<cctype>
  8 #include<queue>
  9 #include<algorithm>
 10 #include<map>
 11 #include<set>
 12 */
 13 #pragma GCC optimize(2)
 14 using namespace std;
 15 typedef long long LL;
 16 typedef unsigned long long uLL;
 17 typedef pair<int,int> pii;
 18 typedef pair<LL,LL> pLL;
 19 typedef pair<double,double> pdd;
 20 const int N=2e6+5;
 21 const int M=1e4+5;
 22 const int inf=2e9+5;
 23 const LL mod=1e9+7;
 24 const double eps=1e-5;
 25 const long double pi=acos(-1.0L);
 26 #define ls (i<<1)
 27 #define rs (i<<1|1)
 28 #define fi first
 29 #define se second
 30 #define pb push_back
 31 #define mk make_pair
 32 #define mem(a,b) memset(a,b,sizeof(a))
 33 LL read()
 34 {
 35     LL x=0,t=1;
 36     char ch;
 37     while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
 38     while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
 39     return x*t;
 40 }
 41 multiset<int> s;//权值线段树维护下一个数字和当前数字的差值
 42 int c[N<<2],t[N],op[N],a[N],cnt[N],q,len;
 43 inline int getid(int x)
 44 {
 45     return lower_bound(t+1,t+len+1,x)-t;
 46 }
 47 void build(int i,int l,int r)
 48 {
 49     c[i]=inf;
 50     if(l==r) return;
 51     int mid=l+r>>1;
 52     build(ls,l,mid);
 53     build(rs,mid+1,r);
 54 }
 55 void update(int i,int l,int r,int pos,int x)
 56 {
 57     if(l==r)
 58     {
 59         c[i]=x;
 60         return ;
 61     }
 62     int mid=l+r>>1;
 63     if(pos<=mid) update(ls,l,mid,pos,x);
 64     else update(rs,mid+1,r,pos,x);
 65     c[i]=min(c[ls],c[rs]);
 66 }
 67 
 68 int query(int i,int l,int r,int ll,int rr)
 69 {
 70     if(ll<=l&&r<=rr) return c[i];
 71     int mid=l+r>>1,t1=inf,t2=inf;
 72     if(mid>=ll) t1=query(ls,l,mid,ll,rr);
 73     if(mid<rr) t2=query(rs,mid+1,r,ll,rr);
 74     return min(t1,t2);
 75 }
 76 int main()
 77 {
 78     s.insert(-1); //加入"人工"边界
 79     s.insert(-1);
 80     s.insert(inf);
 81     q=read();
 82     for(int i=1;i<=q;i++) op[i]=read(),t[i]=a[i]=read();
 83     sort(t+1,t+q+1);
 84     len=unique(t+1,t+q+1)-t-1;
 85     build(1,1,len);
 86     for(int i=1;i<=q;i++)
 87     {
 88         if(op[i]==1)
 89         {
 90             s.insert(a[i]);
 91             int x=getid(a[i]);
 92             cnt[x]++;
 93             if(cnt[x]==1)//新加入一种数字(一个数值对应一种,一个数值也对应离散化后的一个点)
 94             {
 95                 update(1,1,len,x,*s.upper_bound(a[i])-a[i]);
 96                 auto it=s.lower_bound(a[i]);
 97                 it--;
 98                 int tmp=*it;
 99                 int y=getid(tmp);
100                 if(cnt[y]==1) update(1,1,len,y,a[i]-tmp);//如果上一个数字只有一个才更新(如果是两个,那么差值就是0了)
101             }
102             else if(cnt[x]==2) update(1,1,len,x,0);//同一种数字有两个
103         }
104         else if(op[i]==2)
105         {
106             s.erase(s.find(a[i]));
107             int x=getid(a[i]);
108             cnt[x]--;
109             if(cnt[x]==1) update(1,1,len,x,*s.upper_bound(a[i])-a[i]); //从两个变成一个,那么最小差值0 被更新
110             else if(cnt[x]==0)
111             {
112                 update(1,1,len,x,inf);
113                 auto it=s.lower_bound(a[i]);
114                 it--;
115                 int tmp=*it;
116                 int y=getid(tmp);
117                 if(cnt[y]==1) update(1,1,len,y,*s.lower_bound(a[i])-tmp); //这种数字变为0个,当上一个数字只有一个时更新
118             }
119         }
120         else
121         {
122             int flag=0;
123             auto it=s.lower_bound(a[i]);
124             int t1=*it;
125             int t2=*(--it);
126             int t3=*(--it);
127            // printf("...%d %d %d\n",t1,t2,t3);
128             if(a[i]+t2>t1||t2+t3>a[i]) flag=1;//判断第一种情况和第二种情况
129             if(query(1,1,len,getid(a[i]),len)<a[i] ) flag=1;//判断第三种情况
130             if(flag) printf("Yes\n");
131             else printf("No\n");
132         }
133     }
134     return 0;
135 }
136 /*
137 2
138 1 1000000000
139 3 1000000001
140 
141 6
142 1 2
143 1 2
144 2 2
145 3 3
146 1 4
147 3 5
148 
149 7
150 1 3
151 1 2
152 1 100
153 3 99
154 3 1
155 1 100
156 3 1
157 */
H

 

posted @ 2020-07-13 22:28  DeepJay  阅读(211)  评论(0)    收藏  举报