2020牛客多校第二場 H題Happy Triangle(動態開點線段樹)
阿新 • • 發佈:2020-07-18
2020牛客多校第二場 H題Happy Triangle(動態開點線段樹)
題意:q次詢問,3種操作,1:加入一個x,2:刪除一個x,3,問能否在加入的邊中找兩條與x組成3角形。
題解:設三角形3邊a,b,x;
其1:a+b>x;
其2:abs(a-b)<x;
由於其二的特性,我們要儘量找靠的近的a與b既可,例如,a與b間有一個數c,如果a,b滿足公式,那c+b>x,
b-c<x,所以選c不會影響答案,即可以貪心的找靠在一起的邊,那麼要滿足一條我們至少要使b>=x/2+1,這樣a+b才能滿足第一個條件(第一的b要特判),然後我們就找大於b的最小的間隔距離(用動態開點線段樹既可)。
#include<iostream> #include<cstring> #include<map> using namespace std; #define ll long long const ll maxn=1e9+7,inv=2e9+7; ll q,op,x,k,cnt; ll ans[3000007],lc[3000007],rc[3000007]; map<ll,ll>ma; void up(ll &k,ll l,ll r,ll pos,ll z){ if(!k){ k=++cnt; } if(l==r){ ans[k]=z; return; } ll mid=(l+r)/2; if(pos<=mid)up(lc[k],l,mid,pos,z); else{ up(rc[k],mid+1,r,pos,z); } ans[k]=min(ans[lc[k]],ans[rc[k]]); } void add(ll x){ ma[x]++; auto it=ma.lower_bound(x),it2=it; it++; it2--; if(it->first!=inv){ if(it->second<=1){ up(k,1,maxn,it->first,it->first-x); } else{ up(k,1,maxn,it->first,0); } } if(ma[x]<=1){ up(k,1,maxn,x,x-it2->first); } else{ up(k,1,maxn,x,0); } } void del(ll x){ auto it=ma.lower_bound(x),it2=it; it++; it2--; ma[x]--; if(ma[x]==0){ ma.erase(x); up(k,1,maxn,x,inv); if(it->first!=inv&&it->second==1){ up(k,1,maxn,it->first,it->first-it2->first); } } else if(ma[x]==1){ up(k,1,maxn,x,x-it2->first); } } ll findz(ll k,ll l,ll r,ll ql,ll qr){ if(ql<=l&&r<=qr){ return ans[k]; } ll mid=(l+r)/2,ans1=inv,ans2=inv; if(ql<=mid){ ans1=findz(lc[k],l,mid,ql,qr); } if(qr>mid){ ans2=findz(rc[k],mid+1,r,ql,qr); } return min(ans1,ans2); } ll query(ll x){ ll qans=inv; auto it=ma.lower_bound(x/2+1),it2=it; it2--; if(it->first==inv){ return inv; } if(it->second>=2){ qans=0; } if(it->first+it2->first>x){ qans=min(it->first-it2->first,qans); } it++; if(it->first==inv){ return qans; } else{ qans=min(qans,findz(k,1,maxn,it->first,maxn)); } return qans; } int main(){ memset(ans,inv,sizeof(ans)); scanf("%lld",&q); ma[-inv]++; ma[inv]++; while(q--){ scanf("%lld%lld",&op,&x); if(op==1){ add(x); } if(op==2){ del(x); } if(op==3){ if(query(x)<x){ printf("Yes\n"); } else{ printf("No\n"); } } } }