• HDU 5828 Rikka with Sequence (线段树+剪枝优化)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828

    给你n个数,三种操作。操作1是将l到r之间的数都加上x;操作2是将l到r之间的数都开方;操作3是求出l到r之间的和。

    操作1和3就不说了,关键是开方操作。

    一个一个开方,复杂度太高,无疑会T。所以我们来剪枝一下。

    我们可以观察,这里一个数最多开方4,5次(loglogx次)就会到1,所以要是一段区间最大值为1的话,就不需要递归开方下去了。这是一个剪枝。

    如果一段区间的数都是一样大小(最大值等于最小值),那么开方的话,值也会相同。所以只要一次开方就好了,而一次开方也相当于减去 x-sqrt(x)。这是剪枝二。

    有了两个剪枝,原本是过了... 后来数据加强了,就T了,无奈...

      1 //#pragma comment(linker, "/STACK:102400000, 102400000")
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <cstdlib>
      5 #include <cstring>
      6 #include <cstdio>
      7 #include <vector>
      8 #include <cmath>
      9 #include <ctime>
     10 #include <list>
     11 #include <set>
     12 #include <map>
     13 using namespace std;
     14 typedef long long LL;
     15 const int N = 1e5 + 5;
     16 struct SegTree {
     17     int l, r, mid;
     18     LL sum, lazy, Max, Min;
     19 }T[N << 2];
     20 
     21 void build(int p, int l, int r) {
     22     int ls = p << 1, rs = (p << 1)|1;
     23     T[p].l = l, T[p].r = r, T[p].mid = (l + r) >> 1, T[p].lazy = 0;
     24     if(l == r) {
     25         scanf("%lld", &T[p].sum);
     26         T[p].Max = T[p].Min = T[p].sum;
     27         return ;
     28     }
     29     build(ls, l, T[p].mid);
     30     build(rs, T[p].mid + 1, r);
     31     T[p].sum = (T[ls].sum + T[rs].sum);
     32     T[p].Min = min(T[ls].Min, T[rs].Min);
     33     T[p].Max = max(T[ls].Max, T[rs].Max);
     34 }
     35 
     36 void update_add(int p, int l, int r, LL val) {
     37     int ls = p << 1, rs = (p << 1)|1;
     38     if(T[p].l == l && T[p].r == r) {
     39         T[p].Min += val;
     40         T[p].Max += val;
     41         T[p].sum += (r - l + 1) * val;
     42         T[p].lazy += val;
     43         return ;
     44     }
     45     if(T[p].lazy) {
     46         T[ls].lazy += T[p].lazy, T[rs].lazy += T[p].lazy;
     47         T[ls].sum += (T[ls].r - T[ls].l + 1)*T[p].lazy;
     48         T[rs].sum += (T[rs].r - T[rs].l + 1)*T[p].lazy;
     49         T[ls].Max += T[p].lazy, T[ls].Min += T[p].lazy;
     50         T[rs].Max += T[p].lazy, T[rs].Min += T[p].lazy;
     51         T[p].lazy = 0;
     52     }
     53     if(r <= T[p].mid) {
     54         update_add(ls, l, r, val);
     55     }
     56     else if(l > T[p].mid) {
     57         update_add(rs, l, r, val);
     58     }
     59     else {
     60         update_add(ls, l, T[p].mid, val);
     61         update_add(rs, T[p].mid + 1, r, val);
     62     }
     63     T[p].sum = (T[ls].sum + T[rs].sum);
     64     T[p].Min = min(T[ls].Min, T[rs].Min);
     65     T[p].Max = max(T[ls].Max, T[rs].Max);
     66 }
     67 
     68 void update(int p, int l, int r) {
     69     if(T[p].Max == 1) //最大值为1 就不需要开方了
     70         return ;
     71     int ls = p << 1, rs = (p << 1)|1;
     72     if(T[p].l == l && T[p].r == r && T[p].Max == T[p].Min) {
     73         LL temp = T[p].Max - (LL)sqrt(T[p].Max*1.0);
     74         T[p].Max -= temp;
     75         T[p].Min -= temp;
     76         T[p].lazy -= temp;
     77         T[p].sum -= (r - l + 1)*temp;
     78         return ;
     79     }
     80     if(T[p].lazy) {
     81         T[ls].lazy += T[p].lazy, T[rs].lazy += T[p].lazy;
     82         T[ls].sum += (T[ls].r - T[ls].l + 1)*T[p].lazy;
     83         T[rs].sum += (T[rs].r - T[rs].l + 1)*T[p].lazy;
     84         T[ls].Max += T[p].lazy, T[ls].Min += T[p].lazy;
     85         T[rs].Max += T[p].lazy, T[rs].Min += T[p].lazy;
     86         T[p].lazy = 0;
     87     }
     88     if(r <= T[p].mid) {
     89         update(ls, l, r);
     90     }
     91     else if(l > T[p].mid) {
     92         update(rs, l, r);
     93     }
     94     else {
     95         update(ls, l, T[p].mid);
     96         update(rs, T[p].mid + 1, r);
     97     }
     98     T[p].sum = (T[ls].sum + T[rs].sum);
     99     T[p].Min = min(T[ls].Min, T[rs].Min);
    100     T[p].Max = max(T[ls].Max, T[rs].Max);
    101 }
    102 
    103 LL query(int p, int l, int r) {
    104     int ls = p << 1, rs = (p << 1)|1;
    105     if(T[p].l == l && T[p].r == r) {
    106         return T[p].sum;
    107     }
    108     if(T[p].lazy) {
    109         T[ls].lazy += T[p].lazy, T[rs].lazy += T[p].lazy;
    110         T[ls].sum += (T[ls].r - T[ls].l + 1)*T[p].lazy;
    111         T[rs].sum += (T[rs].r - T[rs].l + 1)*T[p].lazy;
    112         T[ls].Max += T[p].lazy, T[ls].Min += T[p].lazy;
    113         T[rs].Max += T[p].lazy, T[rs].Min += T[p].lazy;
    114         T[p].lazy = 0;
    115     }
    116     if(r <= T[p].mid) {
    117         return query(ls, l, r);
    118     }
    119     else if(l > T[p].mid) {
    120         return query(rs, l, r);
    121     }
    122     else {
    123         return query(ls, l, T[p].mid) + query(rs, T[p].mid + 1, r);
    124     }
    125 }
    126 
    127 int main()
    128 {
    129     int n, m, t, c, l, r;
    130     LL val;
    131     scanf("%d", &t);
    132     while(t--) {
    133         scanf("%d %d", &n, &m);
    134         build(1, 1, n);
    135         while(m--) {
    136             scanf("%d %d %d", &c, &l, &r);
    137             if(c == 1) {
    138                 scanf("%lld", &val);
    139                 update_add(1, l, r, val);
    140             }
    141             else if(c == 2) {
    142                 update(1, l, r);
    143             }
    144             else {
    145                 printf("%lld
    ", query(1, l, r));
    146             }
    147         }
    148     }
    149     return 0;
    150 }
    View Code
  • 相关阅读:
    WEB前端工程师 – 职业生涯规划
    求Sn=a+aa+aaa+…+aaa…a的值
    输入一行字符,分别统计出其中英文字母 空格 数字和其他字符的个数
    getchar()的用法!
    求1+2+…+n的和不大于1000的最大自然数n
    编程打印输出*金字塔
    从键盘输入一个整数,判断该数是否回文数.
    编程求"水仙花数"
    编程求出1000以内的完全数
    输入两个正整数,求它们的最大公约数和最小公倍数.
  • 原文地址:https://www.cnblogs.com/Recoder/p/5762299.html
Copyright © 2020-2023  润新知