• Vijos 1404 遭遇战


    背景

    你知道吗,SQ Class的人都很喜欢打CS。(不知道CS是什么的人不用参加这次比赛)。

    描述

    今天,他们在打一张叫DUSTII的地图,万恶的恐怖分子要炸掉藏在A区的SQC论坛服务器!我们SQC的人誓死不屈,即将于恐怖分子展开激战,准备让一个人守着A区,这样恐怖分子就不能炸掉服务器了。(一个人就能守住??这人是机械战警还是霹雳游侠?)
    但是问题随之出现了,由于DustII中风景秀丽,而且不收门票,所以n名反恐精英们很喜欢在这里散步,喝茶。他们不愿意去单独守在荒无人烟的A区,在指挥官的一再命令下,他们终于妥协了,但是他们每个人都要求能继续旅游,于是给出了自己的空闲时间,而且你强大的情报系统告诉了你恐怖份子计划的进攻时间(从s时刻到e时刻)。

    当然,精明的SQC成员不会为你免费服务,他们还要收取一定的佣金(注意,只要你聘用这个队员,不论他的执勤时间多少,都要付所有被要求的佣金)。身为指挥官的你,看看口袋里不多的资金(上头真抠!),需要安排一个计划,雇佣一些队员,让他们在保证在进攻时间里每时每刻都有人员执勤,花费的最少资金。

    格式

    输入格式

    第一行是三个整数n(1≤n≤10000),s和e(1≤s≤e≤90000)。

    接下来n行,描述每个反恐队员的信息:空闲的时间si, ei(1≤si≤ei≤90000)和佣金ci(1≤ci≤300000)。

    输出格式

    一个整数,最少需支付的佣金,如果无解,输出“-1”。

    样例1

    样例输入1

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

    样例输出1

    5
    

    限制

    提示

    敌人从1时刻到4时刻要来进攻,一共有3名反恐队员。第1名从1时刻到3时刻有空,要3元钱(买糖都不够??)。以此类推。

    一共要付5元钱,选用第1名和第2名。

    来源

    SQ CLASS公开编程竞赛2008——Problem D
    Source: WindTalker, liuichou, royZhang


    题目大意

      数轴上有一些区间,每个区间有一个费用。要求选择一些区间将$[s, t]$覆盖,问最小的总费用。

    Solution#1 Dynamic Programming & Heap Optimization

      dp是显然的。 用$f[i]$表示将$[s, i]$覆盖的最小费用。

      考虑转移。显然通过能够覆盖点$i$的线段进行转移,因此有

    $f[i] = max_{线段j能覆盖点i}left{ f[l_{j} - 1] + w_{j} ight}$

      显然可以用一个堆维护右边的那一坨。

    Code

      1 /**
      2  * Vijos
      3  * Problem#1404
      4  * Accepted
      5  * Time: 98ms
      6  * Memory: 3.48m
      7  */ 
      8 #include <bits/stdc++.h>
      9 #ifndef WIN32
     10 #define Auto "%lld"
     11 #else
     12 #define Auto "%I64d"
     13 #endif
     14 using namespace std;
     15 typedef bool boolean;
     16 
     17 #define ll long long
     18 
     19 typedef class Segment {
     20     public:
     21         int l, r;
     22         int w;
     23         
     24         Segment(int l = 0, int r = 0, int w = 0):l(l), r(r), w(w) {        }
     25         
     26         boolean operator < (Segment b) const {
     27             return l < b.l;
     28         }
     29 }Segment;
     30 
     31 typedef class Heap {
     32     public:
     33         priority_queue<ll, vector<int>, greater<int> > que;
     34         priority_queue<ll, vector<int>, greater<int> > del;
     35         
     36         Heap() {    }
     37 
     38         ll top() {
     39             while (!del.empty() && que.top() == del.top())
     40                 que.pop(), del.pop();
     41             return que.top();
     42         }
     43         
     44         void push(ll x) {
     45             que.push(x);
     46         }
     47         
     48         void remove(ll x) {
     49             del.push(x);
     50         }
     51         
     52         boolean empty() {
     53             return (que.size() == del.size());
     54         }
     55 }Heap;
     56 
     57 int n, s, t;
     58 Segment* ss;
     59 vector<Segment*> *g;
     60 Heap h;
     61 ll *f;
     62 
     63 inline void init() {
     64     scanf("%d%d%d", &n, &s, &t);
     65     ss = new Segment[(n + 1)];
     66     g = new vector<Segment*>[(t - s + 5)]; 
     67     f = new ll[(t - s + 5)];
     68     t = t - s + 1;
     69     for (int i = 1; i <= n; i++) {
     70         scanf("%d%d%d", &ss[i].l, &ss[i].r, &ss[i].w);
     71         ss[i].l = max(ss[i].l - s, 0) + 1;
     72         ss[i].r = max(ss[i].r - s, 0) + 1;
     73         if (ss[i].r > t)    ss[i].r = t;
     74     }
     75 }
     76 
     77 inline void solve() {
     78     int p = 1;
     79     f[0] = 0;
     80     sort (ss + 1, ss + n + 1);
     81     for (int i = 1; i <= t; i++) {
     82         while (p <= n && ss[p].l == i) {
     83             h.push(f[ss[p].l - 1] + ss[p].w);
     84             g[ss[p].r].push_back(ss + p);
     85             p++;
     86         }
     87         if (h.empty()) {
     88             puts("-1");
     89             return;
     90         }
     91         f[i] = h.top();
     92         for (int j = 0; j < (signed)g[i].size(); j++)
     93             h.remove(f[g[i][j]->l - 1] + g[i][j]->w);
     94         g[i].clear();
     95     }
     96     printf(Auto"
    ", f[t]);
     97 }
     98 
     99 int main() {
    100     init();
    101     solve();
    102     return 0;
    103 }
    Solution 1

    Solution#2 Shortest Path & Segment Tree Optimization

      其实把dp的转移变成边,然后发现巧的是每条区间的前一个点,向区间上的所有整点连边。

      于是写个线段树建图优化(其实没什么高端的,就是建虚点,防止重复的连边,然后再加点连边的技巧就好了)。

    Code

      1 /**
      2  * Vijos
      3  * Problem#1404
      4  * Accepted
      5  * Time: 606ms
      6  * Memory: 16.0m
      7  */
      8 #include <bits/stdc++.h>
      9 #ifndef WIN32
     10 #define Auto "%lld"
     11 #else
     12 #define Auto "%I64d"
     13 #endif
     14 using namespace std;
     15 typedef bool boolean;
     16 
     17 #define ll long long
     18 #define pii pair<int, int>
     19 #define fi first
     20 #define sc second
     21 
     22 const signed ll llf = (signed ll) (~0ull >> 1);
     23 
     24 int n, s, t;
     25 vector<pii> *g;
     26 ll *f;
     27 boolean *vis;
     28 
     29 inline void init() {
     30     scanf("%d%d%d", &n, &s, &t);
     31     t = t - s + 1;
     32     int siz = ((t + 1) << 2) + 5;
     33     g = new vector<pii>[siz];
     34     f = new ll[siz];
     35     vis = new boolean[siz];
     36     fill(vis, vis + siz, false);
     37     fill(f, f + siz, llf >> 1);
     38 }
     39 
     40 void build(int p, int l, int r) {
     41     if (l == r)    return;
     42     int mid = (l + r) >> 1;
     43     g[p].push_back(pii(p << 1, 0));
     44     g[p].push_back(pii((p << 1) | 1, 0));
     45     build(p << 1, l, mid);
     46     build((p << 1) | 1, mid + 1, r);
     47 }
     48 
     49 int query(int p, int l, int r, int idx) {
     50     if (l == r)
     51         return p;
     52     int mid = (l + r) >> 1;
     53     if (idx <= mid)
     54         return query(p << 1, l, mid, idx);
     55     return query((p << 1) | 1, mid + 1, r, idx);
     56 }
     57 
     58 void query(int p, int l, int r, int ql, int qr, int st, int w) {
     59     if (l == ql && r == qr)    {
     60         g[st].push_back(pii(p, w));
     61         return;
     62     }
     63     int mid = (l + r) >> 1;
     64     if (qr <= mid)
     65         query(p << 1, l, mid, ql, qr, st, w);
     66     else if (ql > mid)
     67         query((p << 1) | 1, mid + 1, r, ql, qr, st, w);
     68     else {
     69         query(p << 1, l, mid, ql, mid, st, w);
     70         query((p << 1) | 1, mid + 1, r, mid + 1, qr, st, w);
     71     }
     72 }
     73 
     74 inline void build() {
     75     build(1, 0, t);
     76     for (int i = 1, l, r, w; i <= n; i++) {
     77         scanf("%d%d%d", &l, &r, &w);
     78         l = max(l - s, 0) + 1;
     79         r = max(r - s, 0) + 1;
     80         if (r > t)    r = t;
     81         int id = query(1, 0, t, l - 1);
     82         query(1, 0, t, l, r, id, w);
     83     }
     84 }
     85 
     86 queue<int> que;
     87 inline void spfa(int s) {
     88     que.push(s);
     89     f[s] = 0;
     90     while (!que.empty()) {
     91         int e = que.front();
     92         que.pop();
     93         vis[e] = false;
     94         for (int i = 0; i < (signed)g[e].size(); i++) {
     95             int eu = g[e][i].fi, w = g[e][i].sc;
     96             if (f[e] + w < f[eu]) {
     97                 f[eu] = f[e] + w;
     98                 if (!vis[eu]) {
     99                     vis[eu] = true;
    100                     que.push(eu);
    101                 }
    102             }
    103         }
    104     }
    105 }
    106 
    107 inline void solve() {
    108     int is = query(1, 0, t, 0);
    109     int it = query(1, 0, t, t);
    110     spfa(is);
    111     if (f[it] == (llf >> 1))
    112         puts("-1");
    113     else
    114         printf(Auto"
    ", f[it]);
    115 }
    116 
    117 int main() {
    118     init();
    119     build();
    120     solve();
    121     return 0;
    122 }
    Solution 2

    Solution#3 Shortest Path

      wtf?纯最短路?没逗我?

      每个区间的前一个点向区间结束点连边。然后每个点向它的前一个点连边,权值为0。

      (神奇的建图方法。。)

      看起来非常朴素,竟然没有dp快

    Code

     1 /**
     2  * Vijos
     3  * Problem#1404
     4  * Accepted
     5  * Time: 285ms
     6  * Memory: 5.75m
     7  */
     8 #include <bits/stdc++.h>
     9 #ifndef WIN32
    10 #define Auto "%lld"
    11 #else
    12 #define Auto "%I64d"
    13 #endif
    14 using namespace std;
    15 typedef bool boolean;
    16 
    17 #define ll long long
    18 #define pii pair<int, int>
    19 #define fi first
    20 #define sc second
    21 
    22 const signed ll llf = (signed ll) (~0ull >> 1);
    23 
    24 int n, s, t;
    25 vector<pii> *g;
    26 ll *f;
    27 boolean *vis;
    28 
    29 inline void init() {
    30     scanf("%d%d%d", &n, &s, &t);
    31     t = t - s + 1;
    32     g = new vector<pii>[t + 1];
    33     f = new ll[t + 1];
    34     vis = new boolean[t + 1];
    35     fill(vis, vis + t + 1, false);
    36     fill(f, f + t + 1, llf >> 1);
    37 }
    38 
    39 inline void build() {
    40     for (int i = 1, l, r, w; i <= n; i++) {
    41         scanf("%d%d%d", &l, &r, &w);
    42         l = max(l - s, 0) + 1;
    43         r = max(r - s, 0) + 1;
    44         if (r > t)    r = t;
    45         g[l - 1].push_back(pii(r, w));
    46     }
    47     for (int i = 1; i <= t; i++)
    48         g[i].push_back(pii(i - 1, 0));
    49 }
    50 
    51 queue<int> que;
    52 inline void spfa(int s) {
    53     que.push(s);
    54     f[s] = 0;
    55     while (!que.empty()) {
    56         int e = que.front();
    57         que.pop();
    58         vis[e] = false;
    59         for (int i = 0; i < (signed)g[e].size(); i++) {
    60             int eu = g[e][i].fi, w = g[e][i].sc;
    61             if (f[e] + w < f[eu]) {
    62                 f[eu] = f[e] + w;
    63                 if (!vis[eu]) {
    64                     vis[eu] = true;
    65                     que.push(eu);
    66                 }
    67             }
    68         }
    69     }
    70 }
    71 
    72 inline void solve() {
    73     spfa(0);
    74     if (f[t] == (llf >> 1))
    75         puts("-1");
    76     else
    77         printf(Auto"
    ", f[t]);
    78 }
    79 
    80 int main() {
    81     init();
    82     build();
    83     solve();
    84     return 0;
    85 }
  • 相关阅读:
    【BZOJ3110】K大数查询(权值线段树套线段树+标记永久化,整体二分)
    【BZOJ3669】魔法森林(LCT)
    art-template前端高性能模板
    spring新心得
    工作流程
    idea操作
    log4j学习
    对实体 "useSSL" 的引用必须以 ';' 分隔符结尾。
    JUnit4学习
    maven搭建
  • 原文地址:https://www.cnblogs.com/yyf0309/p/8421033.html
Copyright © 2020-2023  润新知