Luogu 4433 [COCI2009-2010#1] ALADIN
LOJ 2958
线段树 + 类欧
主要矛盾就是$\sum\limits_{i = l}^{r}Ai \mod B$怎么做。
拆成前缀和相减的形式,有
$$\sum_{i = 0}^{r}(Ai \mod B) - \sum_{i = 0}^{l - 1}(Ai \mod B)$$
我们知道
$$a \mod b = a - \left \lfloor \frac{a}{b} \right \rfloor b$$
那么
$$\sum_{i = 0}^{n}Ai \mod B = \sum_{i = 0}^{n} Ai - \left \lfloor \frac{Ai}{B} \right \rfloor B = \frac{An(n + 1)}{2} - B\sum_{i = 0}^{n}\left \lfloor \frac{Ai}{B} \right \rfloor$$
后面那个东西就是类欧模板中的$f(A, 0, B, n)$。
还有一件事情:$10^9 * 2 * 10^9 / 2 * 10^6 = 10^{24} > long\ long$,所以我写了一个$\text{__int128}$。
因为标记一定要下传,所以似乎不能动态开点而需要离散,但是离散之后注意到线段树一个结点左右儿子可能并不是连续的。
举个栗子,假如我们离散完之后的序列是${1, 5, 7, 9}$,那么一号结点对应的区间是$[1, 9]$,而它的左儿子是$[1, 5]$,右儿子是$[7, 9]$,中间还有一段$[6, 6]$的空缺。所以我们在$up$和算答案的时候需要考虑这段空缺的贡献(可能是我线段树没学好qwq)。
这样子的话效率就很迷人了。
时间复杂度$O(qlog^2n)$。
Code:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; typedef __int128 ILL; const int N = 1e5 + 5; int n, qn, tot = 0, buc[N]; struct Options { int op, l, r, A, B; } q[N]; namespace Fread { const int L = 1 << 15; char buffer[L], *S, *T; inline char Getchar() { if(S == T) { T = (S = buffer) + fread(buffer, 1, L, stdin); if(S == T) return EOF; } return *S++; } template <class T> inline void read(T &X) { char ch; T op = 1; for(ch = Getchar(); ch > '9' || ch < '0'; ch = Getchar()) if(ch == '-') op = -1; for(X = 0; ch >= '0' && ch <= '9'; ch = Getchar()) X = (X << 1) + (X << 3) + ch - '0'; X *= op; } } using namespace Fread; namespace Fwrite { const int L = 1 << 15; char buf[L], *pp = buf; void Putchar(const char c) { if(pp - buf == L) fwrite(buf, 1, L, stdout), pp = buf; *pp++ = c; } template<typename T> void print(T x) { if(x < 0) { Putchar('-'); x = -x; } if(x > 9) print(x / 10); Putchar(x % 10 + '0'); } void fsh() { fwrite(buf, 1, pp - buf, stdout); pp = buf; } template <typename T> inline void write(T x, char ch = 0) { print(x); if (ch != 0) Putchar(ch); fsh(); } } using namespace Fwrite; namespace LikeGcd { ILL solve(ILL a, ILL b, ILL c, ILL n) { if (!a) return (b / c) * (n + 1); if (a >= c || b >= c) return (a / c) * n * (n + 1) / 2 + (b / c) * (n + 1) + solve(a % c, b % c, c, n); if (a < c && b < c) { ILL m = (a * n + b) / c; return n * m - solve(c, c - b - 1, a, m - 1); } return 0; } } namespace SegT { struct Node { int st, A, B; ll sum; bool tag; } s[N << 2]; #define lc p << 1 #define rc p << 1 | 1 #define mid ((l + r) >> 1) #define st(p) s[p].st #define A(p) s[p].A #define B(p) s[p].B #define sum(p) s[p].sum #define tag(p) s[p].tag inline ll calc(int p, int st, int en) { // int st = st(p), en = st(p) + buc[r] - buc[l]; if (!B(p)) return 0; ILL res = 0; res += (ILL)A(p) * (ILL)(st + en) * (ILL)(en - st + 1) / (ILL)2; res -= (ILL)B(p) * (LikeGcd :: solve(A(p), 0, B(p), en) - LikeGcd :: solve(A(p), 0, B(p), st - 1)); return 1LL * res; } inline void up(int p, int l, int r) { sum(p) = sum(lc) + sum(rc); if (buc[mid] + 1 != buc[mid + 1]) { sum(p) += calc(p, st(p) + buc[mid] + 1 - buc[l], st(p) + buc[mid + 1] - 1 - buc[l]); } } inline void down(int p, int l, int r) { if (!tag(p)) return; st(lc) = st(p), st(rc) = st(p) + buc[mid + 1] - buc[l]; A(lc) = A(rc) = A(p); B(lc) = B(rc) = B(p); tag(lc) = tag(rc) = 1; sum(lc) = calc(lc, st(lc), st(lc) + buc[mid] - buc[l]); sum(rc) = calc(rc, st(rc), st(rc) + buc[r] - buc[mid + 1]); tag(p) = 0; } void modify(int p, int l, int r, int x, int y, int A, int B) { if (x <= l && y >= r) { tag(p) = 1; st(p) = buc[l] - buc[x] + 1, A(p) = A, B(p) = B; sum(p) = calc(p, st(p), st(p) + buc[r] - buc[l]); return; } down(p, l, r); if (x <= mid) modify(lc, l, mid, x, y, A, B); if (y > mid) modify(rc, mid + 1, r, x, y, A, B); if (buc[mid + 1] != buc[mid] + 1) { if (buc[x] <= buc[mid] + 1 && buc[y] >= buc[mid + 1] - 1) { A(p) = A, B(p) = B; st(p) = buc[l] - buc[x] + 1; } } up(p, l, r); } ll query(int p, int l, int r, int x, int y) { if (x <= l && y >= r) return sum(p); down(p, l, r); ll res = 0; if (x <= mid) res += query(lc, l, mid, x, y); if (y > mid) res += query(rc, mid + 1, r, x, y); if (buc[mid + 1] != buc[mid] + 1) { if (buc[y] >= buc[mid] + 1 && buc[x] <= buc[mid + 1] - 1) { int ln = max(buc[mid] + 1, buc[x]); int rn = min(buc[mid + 1] - 1, buc[y]); res += calc(p, st(p) + ln - buc[l], st(p) + rn - buc[l]); } } return res; } void ddd(int p, int l, int r) { if (l == r) return; down(p, l, r); ddd(lc, l, mid), ddd(rc, mid + 1, r); } } using namespace SegT; int main() { /* #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif */ read(n), read(qn); for (int i = 1; i <= qn; i++) { read(q[i].op), read(q[i].l), read(q[i].r); buc[++tot] = q[i].l, buc[++tot] = q[i].r; if (q[i].op == 1) read(q[i].A), read(q[i].B); } sort(buc + 1, buc + 1 + tot); tot = unique(buc + 1, buc + 1 + tot) - buc - 1; // for (int i = 1; i <= tot; i++) // printf("%d%c", buc[i], " \n"[i == tot]); for (int i = 1; i <= qn; i++) { q[i].l = lower_bound(buc + 1, buc + 1 + tot, q[i].l) - buc; q[i].r = lower_bound(buc + 1, buc + 1 + tot, q[i].r) - buc; } for (int i = 1; i <= qn; i++) { if (q[i].op == 1) modify(1, 1, tot, q[i].l, q[i].r, q[i].A, q[i].B); else write(query(1, 1, tot, q[i].l, q[i].r), '\n'); /* ddd(1, 1, tot); printf("\n"); for (int j = 1; j <= 9; j++) printf("%d %lld %d %d %d\n", j, sum(j), A(j), B(j), st(j)); */ } return 0; }