NBUT校赛 J Alex’s Foolish Function(分块+延迟标记)
Problem J: Alex’s Foolish Function
Time Limit: 8 Sec Memory Limit: 128 MBSubmit: 18 Solved: 2
Description
Alex has an array F which size is n, initially each element’s value is zero. Now he wants to operate the array, he has 4 different functions:
1) Function A(l, r):
Add the elements between l to r (inclusive) where the ith add i - l + 1, for instance, if l is 4,
Add the elements between l to r (inclusive) where the ith add i - l + 1, for instance, if l is 4,
r is 6 and the elements between 4 to 6 is 3 4 10, after this operation, these elements will become 4 6 13.
2) Function B(l, r):
Add the elements between l to r (inclusive) where the ith add r - i + 1, for instance, if l is 4,
Add the elements between l to r (inclusive) where the ith add r - i + 1, for instance, if l is 4,
r is 6 and the elements between 4 to 6 is 3 4 10, after this operation, these elements will become 6 6 11.
3) Function C(l, r, x):
Set all the elements(between l to r) to x, for instance, if l is 4, r is 6 and the elements
Set all the elements(between l to r) to x, for instance, if l is 4, r is 6 and the elements
between 4 to 6 is 3 4 10, and x = 2, after this operation, these elements will become 2 2 2.
4) Function S(l, r):
Output Fl + Fl+1 + Fl+2 + ...+ Fr.
Output Fl + Fl+1 + Fl+2 + ...+ Fr.
Input
Input start with an integer T(1 <= T <= 5), denoting the number of test case.
For each test case, first line contains n, m (1 <= n <= 200000, 1 <= m <= 100000), denoting the array’size and the number of operations.
Next m lines, each line contains an operation, formatting as
A l r
B l r
C l r x
B l r
C l r x
S l r
Output
For each S Function operations, output the sum.
Sample Input
1
5 4
A 1 3
B 2 5
C 1 1 2
S 1 5
Sample Output
17
正规做法是线段树维护区间的左加、右加或者覆盖信息,然而想用分块写一写。
对于A操作,每一个块维护起始的加数,以及A操作的次数,
对于B操作,每一个块维护末尾的加数,以及B操作的次数,
对于C操作,每一个块维护准备覆盖的值val。
显然对于A操作和B操作维护的信息,是满足区间加法的,即[1,4]A操作一次,[2,4]A操作一次,比如当前块是[2,4],记为Bx,那么我们可以记录起始的加数:(2-1+1)+(2-2+1)=3,A操作次数为2,即arr[2]+=3,arr[3]+=(3+2),arr[4]+=(3+2+2),然后我们可以发现这是一个等差数列,可以用公式快速得到有延迟标记A操作的区间和,即$(Bx.lazy_A+(Bx.lazy_A+Bx.len-1))*Bx.len/2+Bx.sum$,然后B操作也同理,最后加上本身的$Bx.sum$即可(这里要注意AB操作不能重复加Bx.sum);B操作同理;C操作的话由于是覆盖那么在更新的时候把更新到的块的$lazy_c$更新,并把$lazy_A$与$lazy_B$取消掉即可,由于可能$lazy_c$为0,初始值应设为一个不太可能用到的数,比如$-INF$。
代码:
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define fin(name) freopen(name,"r",stdin) #define fout(name) freopen(name,"w",stdout) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 200010; const int M = 450; struct Block { int l, r; LL lazy1, lazy2, lazy3, sum; LL c1, c2; inline int len() { return r - l + 1; } }; Block B[M]; LL arr[N]; int belong[N], unit, bcnt; int n, m; void init() { int i; unit = sqrt(n); bcnt = n / unit; if (n % unit) ++bcnt; for (i = 1; i <= bcnt; ++i) { B[i].l = (i - 1) * unit + 1; B[i].r = i * unit; B[i].sum = 0LL; B[i].lazy1 = 0LL; B[i].lazy2 = 0LL; B[i].lazy3 = -INF; B[i].c1 = B[i].c2 = 0LL; } B[bcnt].r = n; for (i = 1; i <= n; ++i) { arr[i] = 0LL; belong[i] = (i - 1) / unit + 1; } } void pushdown(int bx) { if (B[bx].lazy3 != -INF) { for (int i = B[bx].l; i <= B[bx].r; ++i) arr[i] = B[bx].lazy3; B[bx].lazy3 = -INF; } if (B[bx].lazy1) { for (int i = B[bx].l; i <= B[bx].r; ++i) { arr[i] += + B[bx].lazy1; B[bx].lazy1 += B[bx].c1; } B[bx].lazy1 = 0LL; B[bx].c1 = 0LL; } if (B[bx].lazy2) { for (int i = B[bx].r; i >= B[bx].l; --i) { arr[i] += + B[bx].lazy2; B[bx].lazy2 += B[bx].c2; } B[bx].lazy2 = 0LL; B[bx].c2 = 0LL; } B[bx].sum = 0LL; for (int i = B[bx].l; i <= B[bx].r; ++i) B[bx].sum += arr[i]; } void update(int l, int r, int ops, LL val = 0LL) { int bl = belong[l], br = belong[r]; int i; if (bl == br) { pushdown(bl); if (ops == 1) { for (i = l; i <= r; ++i) { B[bl].sum -= arr[i]; arr[i] = arr[i] + (LL)(i - l + 1LL); B[bl].sum += arr[i]; } } else if (ops == 2) { for (i = r; i >= l; --i) { B[bl].sum -= arr[i]; arr[i] = arr[i] + (LL)(r - i + 1LL); B[bl].sum += arr[i]; } } else if (ops == 3) { for (i = l; i <= r; ++i) { B[bl].sum -= arr[i]; arr[i] = val; B[bl].sum += arr[i]; } } } else { //left pushdown(bl); if (ops == 1) { for (i = l; i <= B[bl].r; ++i) { B[bl].sum -= arr[i]; arr[i] = arr[i] + (LL)(i - l + 1LL); B[bl].sum += arr[i]; } } else if (ops == 2) { for (i = B[bl].r; i >= l; --i) { B[bl].sum -= arr[i]; arr[i] = arr[i] + (LL)(r - i + 1LL); B[bl].sum += arr[i]; } } else if (ops == 3) { for (i = l; i <= B[bl].r; ++i) { B[bl].sum -= arr[i]; arr[i] = val; B[bl].sum += arr[i]; } } //right pushdown(br); if (ops == 1) { for (i = B[br].l; i <= r; ++i) { B[br].sum -= arr[i]; arr[i] = arr[i] + (LL)(i - l + 1LL); B[br].sum += arr[i]; } } else if (ops == 2) { for (i = r; i >= B[br].l; --i) { B[br].sum -= arr[i]; arr[i] = arr[i] + (LL)(r - i + 1LL); B[br].sum += arr[i]; } } else if (ops == 3) { for (i = B[br].l; i <= r; ++i) { B[br].sum -= arr[i]; arr[i] = val; B[br].sum += arr[i]; } } for (i = bl + 1; i < br; ++i) { if (ops == 3) { B[i].lazy3 = val; B[i].c1 = 0LL; B[i].c2 = 0LL; B[i].lazy1 = 0LL; B[i].lazy2 = 0LL; } else if (ops == 2) { B[i].lazy2 += (LL)(r - B[i].r + 1LL); ++B[i].c2; } else if (ops == 1) { B[i].lazy1 += (LL)(B[i].l - l + 1LL); ++B[i].c1; } } } } LL query(int l, int r) { int bl = belong[l], br = belong[r], i; LL sum = 0LL; if (bl == br) { pushdown(bl); for (i = l; i <= r; ++i) sum += arr[i]; return sum; } else { pushdown(bl); pushdown(br); for (i = l; i <= B[bl].r; ++i) sum += arr[i]; for (i = B[br].l; i <= r; ++i) sum += arr[i]; for (i = bl + 1; i < br; ++i) { if (B[i].lazy3 != -INF) sum += (LL)B[i].len() * B[i].lazy3; if (B[i].lazy1) sum += (B[i].lazy1 + B[i].lazy1 + (LL)(B[i].len() - 1LL) * B[i].c1) * (LL)B[i].len() / 2LL; if (B[i].lazy2) sum += (B[i].lazy2 + B[i].lazy2 + (LL)(B[i].len() - 1LL) * B[i].c2) * (LL)B[i].len() / 2LL; if (B[i].lazy3 == -INF) sum += B[i].sum; } return sum; } } int main(void) { // fin("test0.in"); // fout("data_wa.txt"); int tcase, l, r, v; char ops[4]; scanf("%d", &tcase); while (tcase--) { scanf("%d%d", &n, &m); init(); while (m--) { scanf("%s", ops); if (ops[0] == 'A') { scanf("%d%d", &l, &r); update(l, r, 1); } else if (ops[0] == 'B') { scanf("%d%d", &l, &r); update(l, r, 2); } else if (ops[0] == 'C') { scanf("%d%d%d", &l, &r, &v); update(l, r, 3, (LL)v); } else { scanf("%d%d", &l, &r); printf("%lld\n", query(l, r)); } } } return 0; }