1. 程式人生 > 實用技巧 >2020牛客多校訓練賽(第二場)補題

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