题意:N个数Q次操作。一共两种操作:Q l r :询问[l,r]这个区间里的数字和,C l r c: [l,r]区间里的每个数都加上c。1 ≤ N,Q ≤ 100000.
方法:线段树的成段更新。注意懒惰标记。这只是为了有个模板。易错点在代码中以下划线标注。
//16:06 #include <cstdio> #include <cstring> #define N 100010 #define lson l, mid, rt<<1 #define rson mid+1, r, rt<<1|1 long long sum[N<<2]; long long col[N<<2];//一直WA,只因这里写成Int。这个和上面那个要同个类型才是。 void pushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void pushDown(int len, int rt) { if (col[rt]) { col[rt<<1] += col[rt]; col[rt<<1|1] += col[rt]; sum[rt<<1] += (len-len/2)*col[rt]; sum[rt<<1|1] += (len/2)*col[rt]; col[rt] = 0; } } void build(int l, int r, int rt) { col[rt] = 0; if (l==r) { scanf("%lld", &sum[rt]); return; } int mid = (l+r)/2; build(lson); build(rson); pushUp(rt); } void update(int L, int R, int v, int l, int r, int rt) { if (L <= l && r <= R) { col[rt] += v; sum[rt] += (r-l+1ll)*v; return; } pushDown(r-l+1, rt); int mid = (l+r)/2; if (L <= mid) update(L,R,v,lson); if (R > mid) update(L,R,v,rson); pushUp(rt); } long long query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return sum[rt]; } pushDown(r-l+1,rt); int mid = (l+r)/2; long long ans = 0; if (L <= mid) ans += query(L,R,lson); if (R > mid) ans += query(L,R,rson); return ans; } int main() { int n, q; while (scanf("%d%d", &n, &q) != EOF) { build(1,n,1); for (int i = 0; i < q; i++) { char com[20]; scanf("%s", com); if (com[0] == 'Q') { int l, r = 0; scanf("%d%d", &l, &r); //printf("query %d %d ", l, r); printf("%lld ", query(l,r,1,n,1)); } else if (com[0] == 'C') { int l, r, add; scanf("%d%d%d", &l, &r, &add); update(l,r,add,1,n,1); } } } return 0; }
另外感觉三个函数有很多重复点,写了一个紧凑版本,不过看起来代码量差不多,而且效率低了呢。
//16:06 #include <cstdio> #include <cstring> #define N 100010 #define lson l, mid, rt<<1 #define rson mid+1, r, rt<<1|1 long long sum[N<<2]; long long col[N<<2]; void pushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void pushDown(int len, int rt) { if (col[rt]) { col[rt<<1] += col[rt]; col[rt<<1|1] += col[rt]; sum[rt<<1] += (len-len/2)*col[rt]; sum[rt<<1|1] += (len/2)*col[rt]; col[rt] = 0; } } long long basicDo(bool isBuild, int L, int R, int v, int l, int r, int rt) { if (isBuild) col[rt] = 0; if (l == r || L <= l && r <= R) { if (isBuild) scanf("%lld", &sum[rt]); col[rt] += v; sum[rt] += (r-l+1ll)*v; return sum[rt]; } pushDown(r-l+1, rt); int mid = (l+r)/2; long long ans = 0; if (isBuild || L<= mid) ans += basicDo(isBuild,L,R,v,lson); if (isBuild || R > mid) ans += basicDo(isBuild,L,R,v,rson); pushUp(rt); return ans; } void build(int l, int r, int rt) { basicDo(true, 0,0,0,l,r, rt); } void update(int L, int R, int v, int l, int r, int rt) { basicDo(false, L, R, v, l, r, rt); } long long query(int L, int R, int l, int r ,int rt) { return basicDo(false, L, R, 0, l, r, rt); } int main() { int n, q; while (scanf("%d%d", &n, &q) != EOF) { build(1,n,1); for (int i = 0; i < q; i++) { char com[20]; scanf("%s", com); if (com[0] == 'Q') { int l, r = 0; scanf("%d%d", &l, &r); //printf("query %d %d ", l, r); printf("%lld ", query(l,r,1,n,1)); } else if (com[0] == 'C') { int l, r, add; scanf("%d%d%d", &l, &r, &add); update(l,r,add,1,n,1); } } } return 0; }