1. 程式人生 > 實用技巧 >2020牛客多校第二場 H題Happy Triangle(動態開點線段樹)

2020牛客多校第二場 H題Happy Triangle(動態開點線段樹)

2020牛客多校第二場 H題Happy Triangle(動態開點線段樹)

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");
            }
        }
    }
}