牛客練習賽56D.小翔和泰拉瑞亞(線段樹+思維)

題目鏈接:https://ac.nowcoder.com/acm/contest/3566/D

題目大意:

給定一個n元素數組,你有m個操作,每次操作可以選擇一個區間[li,ri],將這個區間內的數減少vi,你可以選擇其中一些進行操作,問你最後可以得到的最大值與最小值的差是多少?

思路:

因爲每個操作是對於區間而言,我們不可能去遍歷每個區間,所以需要更好的策略。

又因爲題中說的是最大值與最小值的差,所以我們可以考慮固定一端,選擇另一端。

於是,我們枚舉每個位置i,然後選擇操作,讓i儘可能的小(也就是如果區間x包括了點i,我們就選擇區間x),這樣點i能夠到達理想的最小值,此時我們再查詢整個區間的最大值,就是一種可行的答案了,最後答案取所以位置的最大值就完了。

因爲一個點可能被很多個區間覆蓋,我們並不是暴力加,在從左往右遍歷的過程中,在每個區間的左端點l插入這個區間,在區間的右端點r+1處刪除這個區間,這樣每個區間只會被update兩次,就能更新到每個位置i啦。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
struct TreeNode{
    int l,r;
    ll maxx;
    ll minn;
    ll lazy;
}Tree[maxn<<2];
ll a[maxn];
void push_up(int root){
    Tree[root].maxx=max(Tree[root<<1].maxx,Tree[root<<1|1].maxx);
    Tree[root].minn=min(Tree[root<<1].minn,Tree[root<<1|1].minn);
}
void Build(int root,int l,int r){
    Tree[root].l=l,Tree[root].r=r;
    if(l==r){
        Tree[root].maxx=Tree[root].minn=a[l];
        Tree[root].lazy=0;
        return ;
    }
    int mid=(l+r)>>1;
    Build(root<<1,l,mid);
    Build(root<<1|1,mid+1,r);
    push_up(root);
}
void push_down(int root){
    if(Tree[root].lazy){
        Tree[root<<1].lazy+=Tree[root].lazy;
        Tree[root<<1|1].lazy+=Tree[root].lazy;
        Tree[root<<1].minn+=Tree[root].lazy;
        Tree[root<<1|1].maxx+=Tree[root].lazy;
        Tree[root<<1|1].minn+=Tree[root].lazy;
        Tree[root<<1].maxx+=Tree[root].lazy;
        Tree[root].lazy=0;
    }
}
void update(int root,int l,int r,int v){
    if(Tree[root].l>=l&&Tree[root].r<=r){
        Tree[root].minn+=v;
        Tree[root].maxx+=v;
        Tree[root].lazy+=v;
        return ;
    }
    push_down(root);
    int mid=(Tree[root].l+Tree[root].r)>>1;
    if(r<=mid){
        update(root<<1,l,r,v);
    }
    else if(l>mid){
        update(root<<1|1,l,r,v);
    }
    else{
        update(root<<1,l,mid,v);
        update(root<<1|1,mid+1,r,v);
    }
    push_up(root);
}
ll query(int root,int l,int r,int opt){
    if(Tree[root].l>=l&&Tree[root].r<=r){
        return opt==1?Tree[root].maxx:Tree[root].minn;
    }
    push_down(root);
    int mid=(Tree[root].l+Tree[root].r)>>1;
    if(r<=mid){
        return query(root<<1,l,r,opt);
    }
    else if(l>mid){
        return query(root<<1|1,l,r,opt);
    }
    else{
        if(opt==1){
            return max(query(root<<1,l,mid,opt),query(root<<1|1,mid+1,r,opt));
        }
        else{
            return min(query(root<<1,l,mid,opt),query(root<<1|1,mid+1,r,opt));
        }
    }
}
struct Seg{
    int l,r;
    ll val;
}seg[maxn];
vector<int>L[maxn];
vector<int>R[maxn];
int cmp(const Seg a,const Seg b){
    return a.l<b.l||(a.l==b.l&&a.r<b.r);
}

//快讀

inline int Read()
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}

inline ll Readll()
{
    ll res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}

signed main(){
    int n,m;
    n=Read(),m=Read();
    for(int i=1;i<=n;i++){
        a[i]=Readll();
    }
    Build(1,1,n);
    for(int i=1;i<=m;i++){
        seg[i].l=Read(),seg[i].r=Read(),seg[i].val=Readll();
    }
    sort(seg+1,seg+m+1,cmp);
    for(int i=1;i<=m;i++){
        L[seg[i].l].push_back(i);
        R[seg[i].r+1].push_back(i);
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<L[i].size();j++){
            update(1,seg[L[i][j]].l,seg[L[i][j]].r,-seg[L[i][j]].val);
        }
        for(int j=0;j<R[i].size();j++){
            update(1,seg[R[i][j]].l,seg[R[i][j]].r,seg[R[i][j]].val);
        }
        ll now=query(1,i,i,2);
        ll maxx=query(1,1,n,1);
        ans=max(ans,maxx-now);
    }
    printf("%lld\n",ans);
    return 0;
}

 

發佈了216 篇原創文章 · 獲贊 15 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章