BOJ 451 田田的算术题
2014-08-02 20:54
232 查看
题意:给出一个数列。有两个操作:1.将给定范围内的项按照顺序加上一个等差数列的项。2.求出给定范围的数列项的和。
思路1:区间更改和区间求和的操作,很容易想到了线段树。由于等差数列满足可加性(即对相同范围内的数进行两次操作1,可以看做一次操作1的和),所以必定可以用线段树。
代码如下:
思路二:由于时限是10s,可以利用复杂度为n√n的块状数组。
每个块状数组维护整体的和,和数组内所有元素对等差数列的加减(同样具有可加性)。
如果查询或者修改区间有部分无法完全包含在块状数组中,则暴力的求和和更改。
注意对数组大小的选择。过大过小都不合适。
代码如下:
思路1:区间更改和区间求和的操作,很容易想到了线段树。由于等差数列满足可加性(即对相同范围内的数进行两次操作1,可以看做一次操作1的和),所以必定可以用线段树。
代码如下:
#include <bits/stdc++.h> using namespace std; template<class T> inline bool read(T &n){ T x = 0, tmp = 1; char c = getchar(); while ((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar(); if (c == EOF) return false; if (c == '-') c = getchar(), tmp = -1; while (c >= '0' && c <= '9') x *= 10, x += (c - '0'), c = getchar(); n = x*tmp; return true; } template <class T> inline void write(T n) { if (n < 0) { putchar('-'); n = -n; } int len = 0, data[20]; while (n) { data[len++] = n % 10; n /= 10; } if (!len) data[len++] = 0; while (len--) putchar(data[len] + 48); } typedef long long LL; const int MAXN = 101000; long long a[MAXN]; int T, M, N, Q, l, r, x, d; struct interval{ int left, right, mid; long long sum, delta, x; bool lazy; }; struct SegmentTree{ static const int MAX = 8 * 101000; interval node[MAX]; inline int lson(int n){ return n << 1; } inline int rson(int n){ return (n << 1) | 1; } void build(int l, int r, int n){ int m = (l + r) / 2; node .left = l; node .right = r; node .mid = m; node .sum = node .delta = node .x = 0LL; node .lazy = false; if (l == r){ node .sum = a[l]; return; } build(l, m, lson(n)); build(m + 1, r, rson(n)); node .sum += node[lson(n)].sum + node[rson(n)].sum; } void pushdown(int n){ if (node .left == node .right){ node .lazy = false; return; } //printf("[%d %d]",node .left,node .right); int l = lson(n); node[l].lazy = true; node[l].delta += node .delta; node[l].x += node .x; long long n1 = node .mid - node .left + 1; node[l].sum += node .x * n1 + n1 * (n1 - 1) / 2 * node .delta; //printf("lson: %lld ",node[l].sum); int r = rson(n); node[r].lazy = true; node[r].delta += node .delta; long long a1 = node .x + (node .mid - node .left + 1) * node .delta; node[r].x += a1; long long n2 = node .right - node .mid; node[r].sum += a1 * n2 + n2 * (n2 - 1) / 2 * node .delta; //printf("rson: %lld\n",node[r].sum); node .lazy = false; node .delta = node .x = 0LL; } long long sum(int l, int r, int n){ if(node .left == node .right) return node .sum; if(l <= node .left && node .right <= r) return node .sum; if(node .lazy) pushdown(n); long long ans = 0LL; if (l <= node .mid) ans += sum(l, r, lson(n)); if (r > node .mid) ans += sum(l, r, rson(n)); return ans; } void modify(int l, int r, long long x, long long d, int n){ if(node .left == node .right){ node .sum += x; return; } if (l <= node .left && node .right <= r){ node .lazy = true; node .delta += d; node .x += x; long long n1 = r - l + 1; node .sum += n1 * x + n1 *(n1 - 1) / 2 * d; //printf("m: %d %d\n",l,r); return; } if(node .lazy) pushdown(n); long long nn = r - l + 1; node .sum += nn * x + nn * (nn - 1) / 2 * d; if (r <= node .mid) modify(l, r, x, d, lson(n)); else if (l > node .mid) modify(l, r, x, d, rson(n)); else{ modify(l, node .mid, x, d, lson(n)); modify(node .mid + 1, r, x + (node .mid - l + 1) * d, d, rson(n)); } } }; SegmentTree s; int main(void) { //freopen("input.txt", "r", stdin); //freopen("out.txt", "w", stdout); read(T); while (T--){ read(N), read(M); for (int i = 1; i <= N; ++i) read(a[i]); s.build(1, N, 1); for (int i = 0; i < M; ++i){ read(Q), read(l), read(r); if (Q == 2) write(s.sum(l, r, 1)),puts(""); else{ read(x), read(d); s.modify(l, r, x, d, 1); } } } return 0; }
思路二:由于时限是10s,可以利用复杂度为n√n的块状数组。
每个块状数组维护整体的和,和数组内所有元素对等差数列的加减(同样具有可加性)。
如果查询或者修改区间有部分无法完全包含在块状数组中,则暴力的求和和更改。
注意对数组大小的选择。过大过小都不合适。
代码如下:
#include <bits/stdc++.h> using namespace std; template<class T> inline bool read(T &n){ T x = 0, tmp = 1; char c = getchar(); while ((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar(); if (c == EOF) return false; if (c == '-') c = getchar(), tmp = -1; while (c >= '0' && c <= '9') x *= 10, x += (c - '0'), c = getchar(); n = x*tmp; return true; } template <class T> inline void write(T n) { if (n < 0) { putchar('-'); n = -n; } int len = 0, data[20]; while (n) { data[len++] = n % 10; n /= 10; } if (!len) data[len++] = 0; while (len--) putchar(data[len] + 48); } const int B = 250; const int MAX = 100100; int T,M,N,Q; int l,r,x,d; long long a[MAX]; struct buc{ long long sum; long long d,x; void clear(){ sum = d = x = 0LL; } } bucket[MAX / B]; long long getsum(int l, int r){ long long ans = 0; while(l < r && l % B != 0){ int id = l / B; int pos = l - id * B; ans += a[l] + bucket[id].x + pos * bucket[id].d; l++; } while(l < r && r % B != 0){ r--; int id = r / B; int pos = r - id * B; ans += a[r] + bucket[id].x + pos * bucket[id].d; } while(l < r){ int id = l / B; ans += bucket[id].sum; l += B; } return ans; } void update(int l,int r,long long x,long long d) { int cnt = 0; while(l < r && l % B != 0){ int id = l / B; long long aa = x + cnt * d; a[l] += aa; bucket[id].sum += aa; cnt++,l++; } while(l + B < r){ int id = l / B; bucket[id].sum += B * (x + cnt * d) + B *(B - 1) / 2 * d ; bucket[id].x += x + cnt * d; bucket[id].d += d; l += B,cnt += B; } while(l < r){ int id = l / B; long long aa = x + cnt * d; a[l] += aa; bucket[id].sum += aa; cnt++,l++; } } int main(void) { //freopen("input.txt","r",stdin); //freopen("out.txt","w",stdout); read(T); while(T--){ read(N),read(M); for(int i = 0 ; i < N / B + 1; i++) bucket[i].clear(); for(int i = 0 ; i< N; ++i) read(a[i]); for(int i = 0 ; i< N; ++i){ int id = i / B; bucket[id].sum += a[i]; } for(int i = 0; i< M; ++i){ read(Q); if(Q == 2){ read(l),read(r); printf("%lld\n",getsum(l-1,r)); } else{ read(l),read(r),read(x),read(d); update(l-1,r,(long long)x,(long long)d); } } } return 0; }
相关文章推荐
- boj 451 田田的算数题 区间更新树状数组
- 后缀数组模板-boj477.新来的小妹妹 & boj477. 田田背课文
- BOJ 438 田田的公司
- BOJ 480 田田背课文
- 一道趣味算术题
- 163邮件群发时出现退信错误明晰! 常见451 550错误
- boj 1343汉诺塔 递归问题 多谢大牛的代码和讲解 我需要多联系类似题目
- boj1074_Candy的魔法
- BOJ1499 合法食物链 floyd
- o.boj 1053 R2
- o.boj 1436 门牌号
- o.boj 1495 麻烦的名词复数
- BOJ 331 树形DP
- NYOJ 451(组合数+全错位)
- IIS的FTP出错: 451 No mapping for the unicode character exists in the target multi-byte code page
- FTP提示“451 No mapping for the Unicode character” 错误
- edgeserver服务器队列数据很多,出现451 4.4.0 dns query failed
- BOJ 2773 第K个与m互质的数
- BOJ 84 Single Number
- BOJ 396~400. 整合