外国人的数据结构题真耿直
唯一有难度的操作就是区间取模,然而这个东西可以暴力弄一下,因为一个数$x$被取模不会超过$logn$次。
证明如下(假设$x Mod y$):
如果$y leq frac{x}{2}$那么$x$取模之后会小于$frac{x}{2}$,而如果$y > frac{x}{2}$时,$x$取模之后一定也会小于$frac{x}{2}$
然后就暴力一个一个取过去就好了,还有一个算是剪枝的优化,我们可以顺便维护一下区间最大值,如果区间最大值都小于当前的模数的话,那么就直接$return$好了。
仍然不会算时间复杂度。
丢个模板。
Code:
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int N = 1e5 + 5; int n, qn; ll a[N]; template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > '9'|| ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline ll max(ll x, ll y) { return x > y ? x : y; } namespace SegT { ll s[N << 2], maxn[N << 2]; #define lc p << 1 #define rc p << 1 | 1 #define mid ((l + r) >> 1) inline void up(int p) { if(p) { s[p] = s[lc] + s[rc]; maxn[p] = max(maxn[lc], maxn[rc]); } } void build(int p, int l, int r) { if(l == r) { s[p] = maxn[p] = a[l]; return; } build(lc, l, mid); build(rc, mid + 1, r); up(p); } void modify(int p, int l, int r, int x, ll v) { if(x == l && x == r) { s[p] = maxn[p] = v; return; } if(x <= mid) modify(lc, l, mid, x, v); else modify(rc, mid + 1, r, x, v); up(p); } void doMod(int p, int l, int r, int x, int y, ll v) { if(maxn[p] < v) return; if(l == r) { s[p] %= v, maxn[p] %= v; return; } if(x <= mid) doMod(lc, l, mid, x, y, v); if(y > mid) doMod(rc, mid + 1, r, x, y, v); up(p); } ll query(int p, int l, int r, int x, int y) { if(x <= l && y >= r) return s[p]; ll res = 0LL; if(x <= mid) res += query(lc, l, mid, x, y); if(y > mid) res += query(rc, mid + 1, r, x, y); return res; } } using namespace SegT; int main() { read(n), read(qn); for(int i = 1; i <= n; i++) read(a[i]); build(1, 1, n); for(int op, x, y; qn--; ) { read(op); if(op == 1) read(x), read(y), printf("%lld ", query(1, 1, n, x, y)); if(op == 2) { read(x), read(y); ll v; read(v); doMod(1, 1, n, x, y, v); } if(op == 3) { read(x); ll v; read(v); modify(1, 1, n, x, v); } } return 0; }