zoukankan      html  css  js  c++  java
  • hdu 3207 Highway

    http://acm.hdu.edu.cn/showproblem.php?pid=3207

      一道看上去好像是线段树的题,不过因为有两种操作(区间增加相同的数,以及将区间中比给出的数小的数更新成给出的数),所以用一般的线段数是不能正确更新的。这题应该是可以用线段树做的,因为在统计里的时间第一的人是貌似是用O(nlogn)的方法的。

      一共三种操作:

      1、如果区间连续,区间减少相同的数

      2、区间增加相同的数

      3、区间中比给出的数小的数都更新成给出的数

      如果某个数小于等于0,那么那个数的位置断裂,而且不能修复!

      这题一个比较简单的,而且不超时的方法是用类似二级检索的方法进行更新块状数组。因为线段树的更新延迟不止一个单位的时间,所以在多次的操作一或二和操作三交替进行,问题就会产生,所以要用二级检索,将区间分成每份长度都是sqrt(n)的段,每次都直接对段进行更新。假如将增加减少和操作三合成一个,那么多组操作同时更新会造成一定的问题。但是二级检索就不一样了,顺序O(sqrt(n))更新,这样更新就不会产生超过1个时间单位的延迟了。

      每段需要记录元素的数组,一个记录最小值,一个记录增加量,一个记录当前要增加到的值,另外还要一个记录最大减少值(小于0的最小值)。

    暴力代码以及随机数据生成器:

    View Code
      1 #define prog 1
      2 
      3 #if prog == 1
      4 
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <ctime>
      8 #include <cstdlib>
      9 #include <algorithm>
     10 
     11 using namespace std;
     12 
     13 int main() {
     14     int T;
     15 
     16     freopen("in", "w", stdout);
     17     scanf("%d", &T);
     18     srand(time(NULL));
     19     while (T--) {
     20         int n = 100;
     21         int m = rand() % 20 + 11;
     22         int init = rand() % 900 + 101;
     23 
     24         printf("%d %d %d\n", n, m, init);
     25         while (m--) {
     26             int s = rand() % n + 1;
     27             int t = rand() % n + 1;
     28 
     29             if (s > t) swap(s, t);
     30             printf("%d %d %d %d\n", (rand() % 4) % 3 + 1, s, t, rand() % 1000 + 1);
     31         }
     32         puts("");
     33     }
     34     puts("0 0 0");
     35 
     36     return 0;
     37 }
     38 
     39 #endif
     40 
     41 #if prog == 2
     42 
     43 #include <cstdio>
     44 #include <cstring>
     45 #include <algorithm>
     46 #include <cstdlib>
     47 
     48 using namespace std;
     49 
     50 const int maxn = 100001;
     51 bool Break[maxn];
     52 int Dur[maxn], INIT;
     53 
     54 void init(int size) {
     55     for (int i = 1; i <= size; i++) {
     56         Break[i] = false;
     57         Dur[i] = INIT;
     58     }
     59 }
     60 
     61 bool can(int l, int r) {
     62     while (l <= r) {
     63         if (Break[l]) return false;
     64         l++;
     65     }
     66 
     67     return true;
     68 }
     69 
     70 void mod(int l, int r, int d) {
     71     while (l <= r) {
     72         Dur[l] = max(Dur[l], d);
     73         if (Dur[l] <= 0) Break[l] = true;
     74         l++;
     75     }
     76 }
     77 
     78 void add(int l, int r, int d) {
     79     while (l <= r) {
     80         Dur[l] += d;
     81         if (Dur[l] <= 0) Break[l] = true;
     82         l++;
     83     }
     84 }
     85 
     86 int main() {
     87     int N, M;
     88 
     89     freopen("in", "r", stdin);
     90     freopen("cmp", "w", stdout);
     91     while (~scanf("%d%d%d", &N, &M, &INIT) && (N + M + INIT)) {
     92         init(N);
     93 
     94         int cnt = 0;
     95 
     96         for (int i = 1; i <= M; i++) {
     97             int s, t, d, op;
     98 
     99             scanf("%d%d%d%d", &op, &s, &t, &d);
    100             switch (op) {
    101             case 1 :
    102                 if (can(s, t)) {
    103                     printf("Pass %d\n", i);
    104                     cnt++;
    105                     add(s, t, -d);
    106                 }
    107                 break;
    108             case 2 :
    109                 add(s, t, d);
    110                 break;
    111             case 3 :
    112                 mod(s, t, d);
    113                 break;
    114             }
    115         }
    116         printf("%d\n", cnt);
    117     }
    118 
    119     return 0;
    120 }
    121 
    122 
    123 #endif

    代码如下:

    View Code
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <cstdlib>
      5 #include <cassert>
      6 #include <cmath>
      7 
      8 using namespace std;
      9 
     10 #define lson l, m, rt << 1
     11 #define rson m + 1, r, rt << 1 | 1
     12 
     13 const int maxn = 100001;
     14 const int segCnt = 400;
     15 const int inf = 0x7f7f7f7f;
     16 
     17 int INIT, segLen = segCnt;
     18 struct Segment {
     19     int e[segCnt];
     20     int Min;
     21     int add;
     22     int addTo;
     23     int lowest;
     24 
     25     void init() {
     26         Min = INIT;
     27         for (int i = 0; i < segLen; i++) {
     28             e[i] = INIT;
     29         }
     30         add = addTo = lowest = 0;
     31     }
     32 
     33     void update() {
     34         Min = inf;
     35         for (int i = 0; i < segLen; i++) {
     36             if (e[i] <= abs(lowest)) e[i] = 0;
     37             if (e[i]) {
     38                 e[i] += add;
     39                 e[i] = max(e[i], addTo);
     40             }
     41             Min = min(Min, e[i]);
     42         }
     43         add = addTo = lowest = 0;
     44     }
     45 
     46     void Add(int l, int r, int d) {
     47         for (int i = l; i <= r; i++) {
     48             if (e[i]) {
     49                 e[i] = max(e[i] + d, 0);
     50             }
     51         }
     52         Min = inf;
     53         for (int i = 0; i < segLen; i++) {
     54             Min = min(Min, e[i]);
     55         }
     56     }
     57 
     58     void AddTo(int l, int r, int d) {
     59         for (int i = l; i <= r; i++) {
     60             if (e[i]) {
     61                 e[i] = max(e[i], d);
     62             }
     63         }
     64         Min = inf;
     65         for (int i = 0; i < segLen; i++) {
     66             Min = min(Min, e[i]);
     67         }
     68     }
     69 
     70     void show() {
     71         puts("Elements: ");
     72         for (int i = 0; i < segLen; i++) {
     73             printf(" %d", e[i]);
     74         }
     75         puts("");
     76         printf("min %d add %d addto %d lowest %d\n", Min, add, addTo, lowest);
     77         puts("~~~");
     78     }
     79 } seg[segCnt];
     80 
     81 bool noBreak(int _l, int _r) {
     82     int segL = _l / segLen, segR = _r / segLen;
     83     int restL = _l % segLen, restR = _r % segLen;
     84 
     85 //    printf("%d %d\n", segL, segR);
     86     if (segL != segR) {
     87         seg[segL].update();
     88         seg[segR].update();
     89 
     90         for (int i = restL; i < segLen; i++) {
     91             if (!seg[segL].e[i]) return false;
     92         }
     93         for (int i = 0; i <= restR; i++) {
     94             if (!seg[segR].e[i]) return false;
     95         }
     96         for (int i = segL + 1; i < segR; i++) {
     97             if (!seg[i].Min) return false;
     98         }
     99     } else {
    100         seg[segL].update();
    101 
    102         for (int i = restL; i <= restR; i++) {
    103             if (!seg[segL].e[i]) return false;
    104         }
    105     }
    106 
    107     return true;
    108 }
    109 
    110 void Add(int _l, int _r, int _d) {
    111     int segL = _l / segLen, segR = _r / segLen;
    112     int restL = _l % segLen, restR = _r % segLen;
    113 
    114     if (segL != segR) {
    115         seg[segL].update();
    116         seg[segR].update();
    117 
    118         seg[segL].Add(restL, segLen - 1, _d);
    119         seg[segR].Add(0, restR, _d);
    120         for (int i = segL + 1; i < segR; i++) {
    121             seg[i].add += _d;
    122             if (seg[i].Min) seg[i].Min += _d;
    123             if (seg[i].addTo) seg[i].addTo += _d;
    124         }
    125     } else {
    126         seg[segL].update();
    127 
    128         seg[segL].Add(restL, restR, _d);
    129     }
    130 }
    131 
    132 bool Sub(int _l, int _r, int _d) {
    133 
    134     if (noBreak(_l, _r)) {
    135 //        puts("noBreak");
    136         int segL = _l / segLen, segR = _r / segLen;
    137         int restL = _l % segLen, restR = _r % segLen;
    138 
    139         if (segL != segR) {
    140             seg[segL].update();
    141             seg[segR].update();
    142 
    143             seg[segL].Add(restL, segLen - 1, -_d);
    144             seg[segR].Add(0, restR, -_d);
    145             for (int i = segL + 1; i < segR; i++) {
    146                 seg[i].add -= _d;
    147                 seg[i].addTo = max(seg[i].addTo - _d, 0);
    148                 seg[i].Min = max(seg[i].Min - _d, 0);
    149                 if (!seg[i].addTo) seg[i].lowest = min(seg[i].lowest, seg[i].add);
    150             }
    151         } else {
    152             seg[segL].update();
    153 
    154             seg[segL].Add(restL, restR, -_d);
    155         }
    156 
    157         return true;
    158     }
    159     return false;
    160 }
    161 
    162 void AddTo(int _l, int _r, int _d) {
    163     int segL = _l / segLen, segR = _r / segLen;
    164     int restL = _l % segLen, restR = _r % segLen;
    165 
    166     if (segL != segR) {
    167         seg[segL].update();
    168         seg[segR].update();
    169 
    170         seg[segL].AddTo(restL, segLen - 1, _d);
    171         seg[segR].AddTo(0, restR, _d);
    172         for (int i = segL + 1; i < segR; i++) {
    173             if (seg[i].Min < _d && seg[i].addTo < _d) {
    174                 seg[i].addTo = _d;
    175                 if (seg[i].Min) seg[i].Min = _d;
    176             }
    177         }
    178     } else {
    179         seg[segL].update();
    180 
    181         seg[segL].AddTo(restL, restR, _d);
    182     }
    183 }
    184 
    185 int main() {
    186     int N, M;
    187 
    188 //    freopen("in", "r", stdin);
    189 //    freopen("out", "w", stdout);
    190 //
    191     while (~scanf("%d%d%d", &N, &M, &INIT) && (N + M + INIT)) {
    192         segLen = (int)sqrt((double) N) + 1;
    193         int op, a, b, c;
    194         int cnt = 0;
    195 
    196         for (int i = 0; i < segLen; i++) {
    197             seg[i].init();
    198 //            printf("Init %d\n", i);
    199 //            seg[i].show();
    200         }
    201         for (int i = 1; i <= M; i++) {
    202             scanf("%d%d%d%d", &op, &a, &b, &c);
    203             switch (op) {
    204             case 1 :
    205                 if (Sub(a, b, c)) {
    206                     cnt++;
    207 //                    printf("Pass %d\n", i);
    208                 }
    209                 break;
    210             case 2 :
    211                 Add(a, b, c);
    212                 break;
    213             case 3 :
    214                 AddTo(a, b, c);
    215                 break;
    216             }
    217 //            for (int j = 0; j < segLen; j++) {
    218 //                printf("Op %d-%d   %d~%d\n", i, j, segLen * j, segLen * (j + 1) - 1);
    219 //                seg[j].show();
    220 //            }
    221 //            puts("~~~~~~");
    222         }
    223         printf("%d\n", cnt);
    224     }
    225 
    226     return 0;
    227 }

    ——written by Lyon

  • 相关阅读:
    015.现场.快用Scala(4月)
    014.科普.有生产力的Sql语句
    JQuery速记
    草稿
    使用jquery.layout.js构建页眉/页脚/左侧导航/中间展示内容的网页结构
    实践自己的WebSite______流水
    如何生成带注释的DLL文件
    MVC如何在解决方案下创建文件夹
    如何利用子视图
    【草稿】JS中如何操作时间
  • 原文地址:https://www.cnblogs.com/LyonLys/p/hdu_3207_Lyon.html
Copyright © 2011-2022 走看看