L3-017 森森快遞 (30 分)


森森開了一家快遞公司,叫森森快遞。因為公司剛剛開張,所以業務路線很簡單,可以認為是一條直線上的N個城市,這些城市從左到右依次從0到(編號。由於道路限制,第i號城市(,)與第(號城市中間往返的運輸貨物重量在同一時刻不能超過Ci​​公斤。

公司開張后很快接到了Q張訂單,其中j張訂單描述了某些指定的貨物要從Sj​​號城市運輸到Tj​​號城市。這里我們簡單地假設所有貨物都有無限貨源,森森會不定時地挑選其中一部分貨物進行運輸。安全起見,這些貨物不會在中途卸貨。

為了讓公司整體效益更佳,森森想知道如何安排訂單的運輸,能使得運輸的貨物重量最大且符合道路的限制?要注意的是,發貨時間有可能是任何時刻,所以我們安排訂單的時候,必須保證共用同一條道路的所有貨車的總重量不超載。例如我們安排1號城市到4號城市以及2號城市到4號城市兩張訂單的運輸,則這兩張訂單的運輸同時受2-3以及3-4兩條道路的限制,因為兩張訂單的貨物可能會同時在這些道路上運輸。

輸入格式:

輸入在第一行給出兩個正整數N和Q(2, 1),表示總共的城市數以及訂單數量。

第二行給出(個數,順次表示相鄰兩城市間的道路允許的最大運貨重量Ci​​(,)。題目保證每個Ci​​是不超過231​​的非負整數。

接下來Q行,每行給出一張訂單的起始及終止運輸城市編號。題目保證所有編號合法,並且不存在起點和終點重合的情況。

輸出格式:

在一行中輸出可運輸貨物的最大重量。

輸入樣例:

10 6
0 7 8 5 2 3 1 9 10
0 9
1 8
2 7
6 3
4 5
4 2

輸出樣例:

7

樣例提示:我們選擇執行最后兩張訂單,即把5公斤貨從城市4運到城市2,並且把2公斤貨從城市4運到城市5,就可以得到最大運輸量7公斤。

 

題意,給出一些區間,這些區間的最大值是所有小區間取最小,問怎么選擇區間可以使取值最大。

參照大神的做法,首先給區間進行排序,按照右端點升序排序,相同的左端點升序,可以從左往右排開,

然后考慮兩個相鄰區間取組大值問題,如果兩個區間是一個被另一個包含,顯然大的取值受小的取值限制,也就是說選擇小區間最優,比如一個區間是[2,7],另一個是[3,5],前一個區間所能取得的最大值是min([2,3],[3,4],[4,5],[5,6],[6,7]),而后一個區間是min([3,4],[4,5]),顯然后一個區間的約束少,所取值大於等於前一個區間的取值。

如果兩個區間是相交的,相交部分為b,那么設左邊區間是a和b組成,右邊是b和c組成,這個時候怎么判斷,關鍵是看b的取值大小,

如果b最大,這個時候取min(a + c,b)(因為b是公共部分,如果b能承載的了a和c的和,那自然很好,如果不行,就得受b約束),

如果b最小,那不用說兩個區間總的最多也就是取值b,如果b大小折中,那自然還是取b,比如是a>b>c,零右邊區間取值c,中間段剩下b-c,總的就是b了。

所以綜合后兩種情況都是a+c>b,相交就取值min(a+c,b),

排序后可以從左往右一個一個求區間最大值,然后更新這個區間都減去這個值,表示后邊與這個區間相交的受相交部分影響,所以要更新。

代碼:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define inf 0x3f3f3f3f3f
using namespace std;
typedef pair<int,int> pa;
typedef long long ll;
int n,q;
ll ans;
int v[100005];
pa p[100005];
int tree[400005],lazy[400005];
bool cmp(const pa &a,const pa &b) {
    if(a.second == b.second) return a.first < b.first;
    return a.second < b.second;
}
void build(int l,int r,int t) {
    lazy[t] = 0;
    if(l == r) tree[t] = v[l];
    else {
        int mid = (l + r) >> 1;
        build(l,mid,t << 1);
        build(mid + 1,r,t << 1 | 1);
        tree[t] = min(tree[t << 1],tree[t << 1 | 1]);
    }
}
void pushdown(int t) {
    if(lazy[t] == 0) return;
    lazy[t << 1] += lazy[t];
    lazy[t << 1 | 1] += lazy[t];
    tree[t << 1] -= lazy[t];
    tree[t << 1 | 1] -= lazy[t];
    lazy[t] = 0;
}
void update(int l,int r,int t,int L,int R,int d) {
    if(l >= L && r <= R) tree[t] -= d,lazy[t] += d;
    else {
        pushdown(t);
        int mid = (l + r) >> 1;
        if(mid >= L) update(l,mid,t << 1,L,R,d);
        if(mid < R) update(mid + 1,r,t << 1 | 1,L,R,d);
        tree[t] = min(tree[t << 1],tree[t << 1 | 1]);
    }
}
ll query(int l,int r,int t,int L,int R) {
    if(l >= L && r <= R) return tree[t];
    if(l > R || r < L) return inf;
    int mid = (l + r) >> 1;
    ll d = inf;
    pushdown(t);
    if(mid >= L) d = min(d,query(l,mid,t << 1,L,R));
    if(mid < R) d = min(d,query(mid + 1,r,t << 1 | 1,L,R));
    tree[t] = min(tree[t << 1],tree[t << 1 | 1]);
    return d;
}
int main() {
    scanf("%d%d",&n,&q);
    for(int i = 0;i < n - 1;i ++) {
        scanf("%d",&v[i]);
    }
    build(0,n - 2,1);
    for(int i = 0;i < q;i ++) {
        scanf("%d%d",&p[i].first,&p[i].second);
        if(p[i].first > p[i].second) swap(p[i].first,p[i].second);
        p[i].second --;
    }
    sort(p,p + q,cmp);
    for(int i = 0;i < q;i ++) {
        ll d = query(0,n - 2,1,p[i].first,p[i].second);
        ans += d;
        update(0,n - 2,1,p[i].first,p[i].second,d);
    }
    printf("%lld",ans);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM