hdu4902Nice boat(线段树区间更新)

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

题目大意:给你一串序列an,有两种操作,操作1:将区间l-r内的所有值替换成x,操作2:将区间l-r内大于x的数替换成x和a[i]的最大公约数;

思路:本题需要用lazy标记剪枝,操作一需要将区间内的所有值都替换,这是很简单的区间修改,用lazy标记存一下需要替换的值,另外本题需要用节点来表示此节点的左右儿子节点的最大值,这样做的目的是便于操作2中搜寻大于x的数值,在操作2中如果不加剪枝处理,那么只能单纯递归到l==r时修改节点值,这样做的话会TLE,那么此时会考虑到,如果在某个节点下的所有儿子节点的值都相等的话,就不需要递归到l==r时修改,只需要在当前节点修改一下节点的值,并用lazy存一下后序节点需要同样修改的x值,如果要实现这个操作的话,我们需要再引入一个标记laz(表示此节点下所有值都相同),如果某个节点的左右儿子节点的值都相等并且左右儿子的laz标记都是1的话,此节点的laz才是1,(注意:本题中的节点值表示的是左右儿子的最大值,最大值相同不代表此节点下的所有儿子值都相同,因为这个坑,我wa了一发),所以需要将叶子节点的laz都设为1,PushUp的时候求每个节点的laz值,操作2的时候,碰到节点laz值为1的直接修改整个区间就ok了。

AC代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #define ll long long
  7 using namespace std;
  8 const int MAXN = 100010;
  9 
 10 int A[MAXN];
 11 int lazy[MAXN << 2];
 12 int laz[MAXN << 2];
 13 int Sum[MAXN << 2];
 14 
 15 int gcd(int a, int b)
 16 {
 17     if (b > a) return gcd(b, a);
 18     int remind = a % b;
 19     if (remind == 0) return b;
 20     else return gcd(b, remind);
 21 }
 22 
 23 
 24 void PushUp(int rt) {
 25     Sum[rt] = max(Sum[rt << 1], Sum[rt << 1 | 1]);
 26     if (Sum[rt << 1] == Sum[rt << 1 | 1] && (laz[rt << 1] & laz[rt << 1 | 1])) {
 27         laz[rt] = 1;
 28     }
 29     else laz[rt] = 0;
 30 }
 31 void Build(int l, int r, int rt) {
 32     lazy[rt] = -1;
 33     laz[rt] = 0;
 34     if (l == r) {
 35         laz[rt] = 1;
 36         Sum[rt] = A[l];
 37         return;
 38     }
 39     int m = (l + r) >> 1;
 40     Build(l, m, rt << 1);
 41     Build(m + 1, r, rt << 1 | 1);
 42     //PushUp(rt);
 43 }
 44 //void PointUpdate(int L, int C, int l, int r, int rt) {
 45 //    if (l == r) {
 46 //        A[l] += C;
 47 //        Sum[rt] += C;
 48 //        lazy[rt] = 0;
 49 //        return;
 50 //    }
 51 //    int m = (l + r) >> 1;
 52 //    if (L <= m) PointUpdate(L, C, l, m, rt << 1);
 53 //    else PointUpdate(L, C, m + 1, r, rt << 1 | 1);
 54 //    //PushUp(rt);
 55 //}
 56 void PushDown(int rt, int ln, int rn) {
 57     if (lazy[rt] != -1) {
 58         lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];
 59         Sum[rt << 1] = Sum[rt << 1 | 1] = lazy[rt];
 60         lazy[rt] = -1;
 61     }
 62 }
 63 void QjUpdate1(int L, int R, int C, int l, int r, int rt) {
 64 
 65     //if (Sum[rt] == r - l + 1) return;
 66     if (L <= l && r <= R) {
 67         lazy[rt] = C;
 68         Sum[rt] = C;
 69         /*if (l == r) {
 70             A[l] = C;
 71         }*/
 72         return;
 73     }
 74     int m = (l + r) >> 1;
 75     PushDown(rt, m - l + 1, r - m);
 76     if (m >= L) QjUpdate1(L, R, C, l, m, rt << 1);
 77     if (m < R) QjUpdate1(L, R, C, m + 1, r, rt << 1 | 1);
 78     PushUp(rt);
 79 }
 80 void QjUpdate2(int L, int R, int C, int l, int r, int rt) {
 81 
 82     //if (Sum[rt] == r - l + 1) return;
 83     if (L <= l && r <= R && laz[rt]) {
 84         int p = gcd(Sum[rt], C);
 85         //A[l] = p;
 86         Sum[rt] = p;
 87         lazy[rt] = p;
 88         return;
 89     }
 90     //if (l == r) {
 91     //    //lazy[rt] = C;
 92     //    int p = gcd(Sum[rt], C);
 93     //    //A[l] = p;
 94     //    Sum[rt] = p;
 95     //    return;
 96     //}
 97     int m = (l + r) >> 1;
 98     PushDown(rt, m - l + 1, r - m);
 99     if (Sum[rt << 1] > C && L <= m) QjUpdate2(L, R, C, l, m, rt << 1);
100     if (Sum[rt << 1 | 1] > C && R > m) QjUpdate2(L, R, C, m + 1, r, rt << 1 | 1);
101     PushUp(rt);
102 }
103 //ll Query(int L, int R, int l, int r, int rt) {
104 //    if (l >= L && r <= R) {
105 //        return Sum[rt];
106 //    }
107 //    int m = (l + r) >> 1;
108 //    //PushDown(rt, m - l + 1, r - m);
109 //    ll ANS = 0;
110 //    if (m >= L) ANS += Query(L, R, l, m, rt << 1);
111 //    if (m < R) ANS += Query(L, R, m + 1, r, rt << 1 | 1);
112 //    return ANS;
113 //}
114 
115 void out(int l, int r, int rt) {
116 
117     if (l == r) {
118         //cout << Sum[rt] << " ";
119         printf("%d ", Sum[rt]);
120         return;
121     }
122     //if (!lazy[rt]) return;
123     int m = (l + r) >> 1;
124     PushDown(rt, m - l + 1, r - m);
125     out(l, m, rt << 1);
126     out(m + 1, r, rt << 1 | 1);
127     PushUp(rt);
128 }
129 
130 int main() {
131 
132     /*ios::sync_with_stdio(false);
133     cin.tie(0);*/
134 
135     int T;
136     scanf("%d", &T);
137     while (T--) {
138         int n, m;
139         scanf("%d", &n);
140         for (int i = 1; i <= n; i++) {
141             //cin >> A[i];
142             scanf("%d", &A[i]);
143         }
144         Build(1, n, 1);
145         scanf("%d", &m);
146         for (int i = 1; i <= m; i++) {
147             int op, x, y, val;
148             scanf("%d", &op);
149             if (op == 1) {
150                 scanf("%d %d %d", &x, &y, &val);
151                 QjUpdate1(x, y, val, 1, n, 1);
152                 /*out(1, n, 1);
153                 cout << "\n";*/
154             }
155             else {
156                 scanf("%d %d %d", &x, &y, &val);
157                 if (x == 1 && y == 8) {
158                     QjUpdate2(x, y, val, 1, n, 1);
159                     continue;
160                 }
161                 QjUpdate2(x, y, val, 1, n, 1);
162                 /*out(1, n, 1);
163                 cout << "\n";*/
164             }
165         }
166         out(1, n, 1);
167         putchar('\n');
168     }
169 
170     return 0;
171 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值