codeforces 438D The Child and Sequence(线段树:单点更新+区间取模+区间和)
2017-08-03 21:22
465 查看
题意:
一个n个数的序列。对它进行 3 种操作。 1 l r:输入a[l,r]的和 2 l r x:令[l,r]所有数对x取模 3 k x:令a[k] = x 每到操作1时输出和。 (1 ≤ n, m ≤ 1e5). (1 ≤ a[i] ≤ 1e9)
分析:
看到区间更新,应该想到懒惰标记。但是用懒惰标记应该满足两个条件:标记可以合并
可以快速更新区间信息。
但是这道题不满足条件2,也就是无法快速更新区间和。而逐个更新每个数取模,仿佛又太慢了。
正确解法基于一个重要的结论,a % b <= a/2,这就意味着,任何一个数loga[i]次取模以内就能变为0。同时还注意到,a % b = a (a < b)。这两点便可以极大的降低时间复杂度。
至此,便得到解题思路。单点更新和区间和并无特殊之处,而对于每个区间取模操作,如同遍历这个区间所有的数字一样,逐个取模更新。但是若某个区间的区间最大值小于mod,那么这个区间就无需有任何操作。这相当于一个剪枝。所以我们需要两个数组,一个记录区间和,一个记录区间最大值。总的时间复杂度为O(nlognloga[i])。
其实线段树的实质就是一个dfs搜索树的过程,只不过在每次搜索的时候都判断区间是否重合、是否相交、区间某值是否满足条件等等,这些过程的实质就是剪枝。时间复杂度就是靠这些剪枝降到logn的,否则就像遍历一棵树一样是O(n)。
代码
#include <iostream> #include <algorithm> #include <queue> #include <stack> #include <vector> #include <set> #include <cmath> #include <cstdlib> #include <cstring> #include <cstdio> using namespace std; #define ms(a,b) memset(a,b,sizeof(a)) typedef long long ll; #define lson rt*2,l,(r+l)/2 #define rson rt*2+1,(l+r)/2+1,r const int MAXN = 1e5 + 5; const double EPS = 1e-8; const int INF = 0x3f3f3f3f; ll mx[MAXN << 2], sum[MAXN << 2]; int n, m; void pushup(int rt) { mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void build(int rt, int l, int r) { if (l == r) { scanf("%lld", &mx[rt]); sum[rt] = mx[rt]; return; } build(lson); build(rson); pushup(rt); } ll query(int L, int R, int rt, int l, int r) { if (L <= l && R >= r) { return sum[rt]; } if (R <= (l + r) / 2) return query(L, R, lson); else if (L > (l + r) / 2) return query(L, R, rson); else return query(L, R, lson) + query(L, R, rson); } void update(int L, int R, int rt, int l, int r, int mod) { if (L <= l && R >= r) { if (mx[rt] < mod) return; if (l == r) { mx[rt] = sum[rt] = mx[rt] % mod; return; } } if (L <= (l + r) / 2) update(L, R, lson, mod); if (R > (l + r) / 2) update(L, R, rson, mod); pushup(rt); } void change(int rt, int l, int r, int k, int x) { if (l == r) { mx[rt] = x; sum[rt] = x; return; } if (k <= (l + r) / 2) change(lson, k, x); else change(rson, k, x); pushup(rt); } int main() { while (~scanf("%d%d", &n, &m)) { build(1, 1, n); while (m--) { int op, L, R, k, x; scanf("%d", &op); if (op == 1) { scanf("%d%d", &L, &R); printf("%lld\n", query(L, R, 1, 1, n)); } else if (op == 2) { scanf("%d%d%d", &L, &R, &x); update(L, R, 1, 1, n, x); } else { 4000 scanf("%d%d", &k, &x); change(1, 1, n, k, x); } } } return 0; }
相关文章推荐
- codeforces 315 B.Sereja and Array(线段树区间更新+单点更新+单点询问)
- Codeforces 525B. Pasha and String【线段树 区间更新 单点查询】
- hdu 1540 Tunnel Warfare(线段树单点更新+区间合并)
- hdu 3308 线段树单点更新 区间合并
- hdu 1556 Color the ball(线段树 区间更新单点查询)
- CodeForces 276E - Little Girl and Problem on Trees 区间更新..N+1个线段树
- Necklace (线段树单点更新+区间查询+离线操作)
- 学习线段树-【线段树-单点更新,区间求和】hdu 1166 -敌兵布阵
- HDU - 1540Tunnel Warfare(线段树 单点更新 区间查询)
- hdu 5316 Magician(2015多校第三场第1题)线段树单点更新+区间合并
- NYOJ 116 士兵杀敌(二)(线段树—区间求和,单点加值更新)
- HDU1166(线段树单点更新区间查询)
- HDU-1556-Color the ball-线段树+区间更新+单点查询
- HDU.1556 Color the ball (线段树 区间更新 单点查询)
- hdu 1754 线段树区间最大值 单点更新
- CodeForces 339D 线段树 单点更新,记录深度
- 喵哈哈村的魔法考试 Round #2 (Div.2) B.喵哈哈村的种花魔法 线段树 区间更新 单点查询
- A - 敌兵布阵(线段树)(单点更新区间求和)
- CodeForces 276E Little Girl and Problem on Trees(线段树区间更新)
- 4000 HDU 4819 Mosaic(二维线段树区间查询+单点更新模板)