PAT-GPLT L3-017 森森快遞(貪心 + 線段樹)


鏈接:

https://www.patest.cn/contests/gplt/L3-017

 

題意:

給出直線上的N個頂點,(N-1)條邊的限制值(每對相鄰的頂點之間都有一條邊),以及Q個區間(給出起始頂點編號以及終止頂點編號)。
每個區間都可以為該區間的所有邊加上一個附加值,所有區間在某條邊上所累加的附加值不能超過這條邊的限制值。
問:所有區間的附加值總和最大是多少?

 

分析:

先按終點編號(將原來起點與終點編號較大的作為終點編號)從小到大排序,然后貪心選擇:
順序考慮每一個區間,用線段樹快速找到該區間的最小值,然后更新該區間。
最后所有區間能找到的最小值總和就是答案。
至於為什么要按終點編號從小到大排序,而不是按起點編號從小到大排序,或按區間長度從小到大排序,看一下下面的測試數據就明白了。
不過這道題目說每個限制值是不超過2的31次方的非負整數,為什么偏要 long long 才能過呢?

 

代碼:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 typedef long long int LLI;
 6 const LLI INF = 0x3f3f3f3f3f3f3f3f;
 7 const int UP = 1e5 + 5;
 8 
 9 struct SEGMENT_TREE_NODE {
10     LLI v, m; //值,標記
11 } st[UP<<2];
12 
13 struct REGION {
14     int L, R;
15     bool operator < (const REGION& that) const {
16         return R < that.R;
17     }
18 } reg[UP];
19 
20 void build(int root, int L, int R){
21     st[root].m = 0;
22     if(L + 1 == R){
23         scanf("%lld", &st[root].v);
24         return;
25     }
26     int M = L + (R - L) / 2;
27     build(root*2+1, L, M);
28     build(root*2+2, M, R);
29     st[root].v = min(st[root*2+1].v, st[root*2+2].v);
30 }
31 
32 void push_down(int root){
33     if(!st[root].m) return;
34     st[root*2+1].v += st[root].m;
35     st[root*2+2].v += st[root].m;
36     st[root*2+1].m += st[root].m;
37     st[root*2+2].m += st[root].m;
38     st[root].m = 0;
39 }
40 
41 LLI query(int root, int L, int R, int AL, int AR){
42     if(AR <= L || AL >= R) return INF;
43     if(AL <= L && R <= AR) return st[root].v;
44     push_down(root);
45     int M = L + (R - L) / 2;
46     return min(query(root*2+1, L, M, AL, AR), query(root*2+2, M, R, AL, AR));
47 }
48 
49 void update(int root, int L, int R, int AL, int AR, LLI v){
50     if(AR <= L || AL >= R) return;
51     if(AL <= L && R <= AR){
52         st[root].v += v;
53         st[root].m += v;
54         return;
55     }
56     push_down(root);
57     int M = L + (R - L) / 2;
58     update(root*2+1, L, M, AL, AR, v);
59     update(root*2+2, M, R, AL, AR, v);
60     st[root].v = min(st[root*2+1].v, st[root*2+2].v);
61 }
62 
63 int main(){
64     int n, q;
65     scanf("%d%d", &n, &q);
66     build(0, 0, --n);
67 
68     for(int i = 0; i < q; i++){
69         scanf("%d%d", &reg[i].L, &reg[i].R);
70         if(reg[i].L > reg[i].R) swap(reg[i].L, reg[i].R);
71     }
72     sort(reg, reg + q);
73 
74     LLI ans = 0;
75     for(int i = 0; i < q; i++){
76         LLI v = query(0, 0, n, reg[i].L, reg[i].R);
77         ans += v;
78         if(v) update(0, 0, n, reg[i].L, reg[i].R, -v);
79     }
80     printf("%lld\n", ans);
81     return 0;
82 }


測試數據:

input1:

5 3
5 3 3 1
4 1
1 3
3 4

output1:

4

 

input2:

5 3
3 9 9 1
3 1
2 0
2 4

output2:

10

 


免責聲明!

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



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