E. Boring Segments

纯粹的發表於2024-07-28

原題連結

題解

只要求最大值和最小值的差儘量小,也就意味著,權值位於最大值和最小值之間的線段可以任意取

也就是說,我們將線段按權值排序,我們只需要取其中一段區間,然後檢視是否覆蓋了完整的區間,如果是,判斷能否更新最小值

這樣看起來是兩次for迴圈找區間,對於檢視是否完整覆蓋區間的部分,看起來是對區間內每個點+1,然後檢視全域最小值

這樣看起來是 \(O(n^4)\) 的做法

最佳化:
對於區間修改,區間查詢,我們可以用線段樹維護,時間複雜度來到 \(O(n^3 logn)\)

再度最佳化:我們可以遍歷 \(i\) ,檢視以 \(i\) 為右端點時,且能覆蓋全域的最大左端點 \(l\),由於這樣的左端點是遞增的,所以我們可以用雙指標維護,時間複雜度來到 \(O(nlogn)\)

雙指標上樓:我們發現,在遍歷 \(i\) 查詢以 \(i\) 為左/右端點時,滿足條件的 ( 最大/小) 左/右 端點,可以用雙指標維護,只要這樣的 左/右端點 滿足單調性

code

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-x))
using namespace std;
const ll inf=1e18;
ll tree[4000006]={0};
struct node
{
    ll l,r,v;
}seg[300005];
bool cmp(node a,node b)
{
    return a.v<b.v;
}

ll lazytag[4000006]={0};

void pushdown(ll node,ll l,ll r)
{
    tree[node]+=lazytag[node];
    if(l!=r)
    {
        lazytag[node*2]+=lazytag[node];
        lazytag[node*2+1]+=lazytag[node];
    }

    lazytag[node]=0;
}

void update(ll node,ll l,ll r,ll x,ll y,ll val)
{
    if(lazytag[node]) pushdown(node,l,r);

    if(l>y||r<x) return ;

    if(l>=x&&r<=y)
    {
        lazytag[node]=val;
        pushdown(node,l,r);
        return;
    }

    ll mid=(l+r)/2;
    update(node*2,l,mid,x,y,val);update(node*2+1,mid+1,r,x,y,val);

    tree[node]=min(tree[node*2],tree[node*2+1]);
}

void solve()
{
    ll n,m;
    cin>>n>>m;

    for(ll i=1;i<=n;i++)
    {
        cin>>seg[i].l>>seg[i].r>>seg[i].v;
    }

    sort(seg+1,seg+1+n,cmp);

    ll itl=1;

    ll ans=inf;
    for(ll itr=1;itr<=n;itr++)
    {
        update(1,1,m-1,seg[itr].l,seg[itr].r-1,1);
        while(itl<=itr&&tree[1]>0)
        {
            update(1,1,m-1,seg[itl].l,seg[itl].r-1,-1);
            itl++;
        }

       // printf("itl:%d  itr:%d\n",itl,itr);
        if(itl!=1) ans=min(ans,seg[itr].v-seg[itl-1].v);
    }
    cout<<ans;
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    ll TT=1;
    //cin>>TT;
    while(TT--) solve();
    return 0;
}

相關文章