L3-017. 森森快遞
森森開了一家快遞公司,叫森森快遞。因為公司剛剛開張,所以業務路線很簡單,可以認為是一條直線上的N個城市,這些城市從左到右依次從0到(N-1)編號。由於道路限制,第i號城市(i=0, ..., N-2)與第(i+1)號城市中間往返的運輸貨物重量在同一時刻不能超過 Ci公斤。
公司開張后很快接到了Q張訂單,其中第j張訂單描述了某些指定的貨物要從Sj號城市運輸到Tj號城市。這里我們簡單地假設所有貨物都有無限貨源,森森會不定時地挑選其中一部分貨物進行運輸。安全起見,這些貨物不會在中途卸貨。
為了讓公司整體效益更佳,森森想知道如何安排訂單的運輸,能使得運輸的貨物重量最大且符合道路的限制?要注意的是,發貨時間有可能是任何時刻,所以我們安排訂單的時候,必須保證共用同一條道路的所有貨車的總重量不超載。例如我們安排1號城市到4號城市以及2號城市到4號城市兩張訂單的運輸,則這兩張訂單的運輸同時受2-3以及3-4兩條道路的限制,因為兩張訂單的貨物可能會同時在這些道路上運輸。
輸入格式:
輸入在第一行給出兩個正整數N和Q(2 <= N <= 105, 1 <= Q <= 105),表示總共的城市數以及訂單數量。
第二行給出(N-1)個數,順次表示相鄰兩城市間的道路允許的最大運貨重量Ci(i=0, ..., N-2)。題目保證每個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公斤。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<map> #include<set> #define maxn 10010 using namespace std; typedef long long ll; int edge[maxn][maxn]; vector<int> E[maxn]; ll ans = 0; int vis[maxn] = {0}; void dfs( int x, ll sum ) { if( sum > ans ) { ans = sum; } for( int i = 0; i < E[x].size(); i ++ ) { if( !vis[E[x][i]] ) { vis[E[x][i]] = 1; dfs( E[x][i], sum + edge[x][E[x][i]] ); vis[E[x][i]] = 0; } } } int main() { int n, m, a[maxn], t = 1e9; cin >> n >> m; for( int i = 0; i < n - 1; i ++ ) { cin >> a[i]; /* edge[i].push_back( make_pair( i + 1, a[i] ) ); edge[i+1].push_back( make_pair( i, a[i] ) );*/ edge[i][i+1] = a[i]; edge[i+1][i] = a[i]; for( int j = 0; j < i - 1; j ++ ) { t = 1e9; for( int k = j; k < i; k ++ ) { t = min( t, a[k] ); } /*edge[j].push_back( make_pair( i, t ) ); edge[i].push_back( make_pair( j, t ) );*/ edge[i][j] = t; edge[j][i] = t; } } while( m -- ) { int x, y; cin >> x >> y; E[x].push_back(y); E[y].push_back(x); } for( int i = 0; i <= n - 1; i ++ ) { /*for( int j = 0; j < E[i].size(); j ++ ) { cout << E[i][j] << " " << edge[i][E[i][j]] << "--"; } cout << endl;*/ memset( vis, 0, sizeof(vis) ); vis[i] = 1; dfs( i, 0 ); } cout << ans - 1 << endl; return 0; }
比賽后看大佬用線段樹+貪心做的
https://blog.csdn.net/hnust_derker/article/details/79552988
/** 因為一個區間[l, r]的最大貨運量就是min([l, r]), 對於兩個區間[l, r], [L, R] 假設(r <= R) 1. 兩個區間完全不相交, 則最大貨運量就是min([l, r]) + min([L, R]),誰先取誰后取都是一樣 2.[l, r]完全包含於[L, R],那么肯定選擇[l, r]且取其最大貨運量,因為min[l, r] >= min[L, R],如果選擇兩個訂單的話,最大貨運量都 是min[l, r], 但是單獨取[l, r]這個區間, 那么對周圍影響的區間都小, 往左往右才可能有更優的取值, 如果[L, R]這個區間要取的話, 這里的每個值都要減去一個值,且最終[l, r]的結果是一樣的, 所以肯定取[l,r]且保證貨運量最大 3.兩區間相交,如果若干個區間已經按右端點從小到大排好序,相同按左端點排序,假設相交於[L, r], 那么兩個區間的最大值就是 min{min[L, r], min[l, r] + min[L, R]}這個值是不變的,但是如果[L, R]取得大的話, 對后面的可能相交區間最小值影響就大, 所以要對 l, r取盡可能大, L, R取盡可能小 所以就是: 區間已經按右端點從小到大排好序,相同按左端點排序, 然后從左往右,遇到一個區間就取其區間最小值加到ans上去, 然后更新這個區間 */ #include<bits/stdc++.h> typedef long long ll; const ll maxn = 2e5 + 10; const ll INF = 1e10; using namespace std; typedef pair<ll, ll> pa; ll n, m, T, kase = 1; ll C[maxn * 4], lazy[maxn * 4], d[maxn]; pa lst[maxn]; void push_down(ll o) { ll o1 = o << 1, o2 = o << 1 | 1; if(!lazy[o]) return ; lazy[o1] += lazy[o]; lazy[o2] += lazy[o]; C[o1] -= lazy[o]; C[o2] -= lazy[o]; lazy[o] = 0; } void build(ll o, ll l, ll r) { lazy[o] = 0; if(l == r) { C[o] = d[l]; return ; } ll mid = (l + r) >> 1; build(o << 1, l, mid); build(o << 1 | 1, mid + 1, r); C[o] = min(C[o << 1], C[o << 1 | 1]); } ll ql, qr, data; ll query_min(ll o, ll l, ll r) { if(l >= ql && r <= qr) return C[o]; if(l > qr || r < ql) return INF; ll mid = (l + r) >> 1; push_down(o); ll p1 = query_min(o << 1, l, mid); ll p2 = query_min(o << 1 | 1, mid + 1, r); C[o] = min(C[o << 1], C[o << 1 | 1]); return min(p1, p2); } void update(ll o, ll l, ll r) { if(l >= ql && r <= qr) { C[o] -= data; lazy[o] += data; return ; } if(l > qr || r < ql) return ; push_down(o); ll mid = (l + r) >> 1; update(o << 1, l, mid); update(o << 1 | 1, mid + 1, r); C[o] = min(C[o << 1], C[o << 1 | 1]); } int main() { while(scanf("%lld %lld", &n, &m) != EOF) { for(ll i = 0; i < n - 1; i++) scanf("%lld", &d[i]); build(1, 0, n - 2); for(ll i = 0; i < m; i++) { scanf("%lld %lld", &ql, &qr); if(ql > qr) swap(ql, qr); qr--; lst[i] = pa(qr, ql); } ll ans = 0; sort(lst, lst + m); for(int i = 0; i < m; i++) { ql = lst[i].second; qr = lst[i].first; ll mt = query_min(1, 0, n - 2); ans += mt; data = mt; update(1, 0, n - 2); } printf("%lld\n", ans); } return 0; }
