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

 

posted @ 2018-01-07 17:12  Ctfes  阅读(1725)  评论(3编辑  收藏  举报