• 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
    ", 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

  • 相关阅读:
    Windows下 flex + bison 小例子
    MongoDB 启动基于角色的登录认证功能
    多线程中数的原子性加减
    pymongo.errors.OperationFailure: Authentication failed.
    Windows 中 . 和 .. 的区别
    CString常用函数
    string常用函数
    回调函数 小例子
    VS2008兼容安装
    测试代码的执行时间魔法方法%time和%timeit
  • 原文地址:https://www.cnblogs.com/hkxy125/p/8228479.html
Copyright © 2020-2023  润新知