UOJ228 簡單資料結構練習題
阿新 • • 發佈:2018-11-12
Description
傳送門
維護一個數列, 有以下操作:
對[l,r]同時加上x
把[l,r]開根後下取整.
查詢[l,r]之和
n,m \(\leq\)$ 100000, $\(a_i,x \leq 10^5\)
Solution
考慮一個簡易的線段樹,直接對一個區間進行開根. 如果這個區間數字不同就繼續往下遞迴. 因為 開根開不了多少次就會變成1,所以複雜度相對較小.但考慮一種情況:8 9 8 9 8 9 \(\dots\) 這樣變成1後再區間修改變成原來的樣子.然後就會TLE.
怎麼辦呢. 考慮一個小小優化,如果\(Max - \sqrt{Max} = Min - \sqrt{Min}\)
然後就跑過去了, 還跑得飛快.
分析一下複雜度:
對於一個數\(y =a^{2^{k}}\), 我們對他開根是:\(k\)次的, 即\(log_{2}({log_{a}(y)})\). 對於一個數, 我們線上段樹上跳是\(log{n}\)次的.
我們定義勢能V為相鄰兩數的差. 那麼越開根號,V就越小.
顯然,我們一次加法最多讓V增加到最大值, 總勢能為mV, 所以複雜度為\(O((n + m)logN * loglogV)\)
Codes
#include<bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i) #define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i) #define clar(a, b) memset((a), (b), sizeof(a)) #define debug(...) fprintf(stderr, __VA_ARGS__) #define Debug(s) debug("The massage in line %d, Function %s: %s\n", __LINE__, __FUNCTION__, s) typedef long long LL; typedef long double LD; const int BUF_SIZE = (int)1e6 + 10; struct fastIO { char buf[BUF_SIZE], buf1[BUF_SIZE]; int cur, cur1; FILE *in, *out; fastIO() { cur = BUF_SIZE, in = stdin, out = stdout; cur1 = 0; } inline char getchar() { if(cur == BUF_SIZE) fread(buf, BUF_SIZE, 1, in), cur = 0; return *(buf + (cur++)); } inline void putchar(char ch) { *(buf1 + (cur1++)) = ch; if (cur1 == BUF_SIZE) fwrite(buf1, BUF_SIZE, 1, out), cur1 = 0; } inline int flush() { if (cur1 > 0) fwrite(buf1, cur1, 1, out); return cur1 = 0; } }IO; #define getchar IO.getchar #define putchar IO.putchar int read() { char ch = getchar(); int x = 0, flag = 1; for(;!isdigit(ch); ch = getchar()) if(ch == '-') flag *= -1; for(;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; return x * flag; } void write(LL x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar(x % 10 + 48); } void putString(char s[], char EndChar = '\n') { rep(i, 0, strlen(s) - 1) putchar(*(s + i)); if(~EndChar) putchar(EndChar); } #define Maxn 100009 int n, m, a[Maxn]; namespace SGMT_tree { LL Max[Maxn << 2], Min[Maxn << 2], sum[Maxn << 2], tag[Maxn << 2]; #define lc(x) ((x) << 1) #define rc(x) (((x) << 1) | 1) void pushup(int root) { Max[root] = max(Max[lc(root)], Max[rc(root)]); Min[root] = min(Min[lc(root)], Min[rc(root)]); sum[root] = sum[lc(root)] + sum[rc(root)]; } void pushdown(int root, int l, int r) { LL v = tag[root]; if(v) { int mid = (l + r) >> 1; Max[lc(root)] += v, Min[lc(root)] += v, tag[lc(root)] += v; sum[lc(root)] += 1ll * v * (mid - l + 1); Max[rc(root)] += v, Min[rc(root)] += v, tag[rc(root)] += v; sum[rc(root)] += 1ll * v * (r - mid); tag[root] = 0; } } void build(int root, int l, int r) { if(l == r) { Max[root] = Min[root] = sum[root] = a[l]; tag[root] = 0; return ; } int mid = (l + r) >> 1; build(lc(root), l, mid); build(rc(root), mid + 1, r); pushup(root); } void modify(int root, int l, int r, int x, int y, LL v) { if(l > r || r < x || l > y) return ; if(x <= l && r <= y) { Max[root] += v, Min[root] += v, tag[root] += v; sum[root] += 1ll * v * (1ll * r - l + 1); return; } int mid = (l + r) >> 1; pushdown(root, l, r); modify(lc(root), l, mid, x, y, v); modify(rc(root), mid + 1, r, x, y, v); pushup(root); } void modify(int root, int l, int r, int x, int y) { if(l > r || r < x || l > y) return ; if(x <= l && r <= y) { if(Max[root] - ((int)sqrt(Max[root])) == Min[root] - ((int)sqrt(Min[root]))) { LL v = -Max[root] + ((int)sqrt(Max[root])); Max[root] += v, Min[root] += v, tag[root] += v, sum[root] += 1ll * v * (r - l + 1); return ; } } int mid = (l + r) >> 1; pushdown(root, l, r); modify(lc(root), l, mid, x, y); modify(rc(root), mid + 1, r, x, y); pushup(root); } LL query(int root, int l, int r, int x, int y) { if(l > r || r < x || l > y) return 0; if(x <= l && r <= y) return sum[root]; int mid = (l + r) >> 1; LL res = 0; pushdown(root, l, r); res += query(lc(root), l, mid, x, y); res += query(rc(root), mid + 1, r, x, y); pushup(root); return res; } } namespace INIT { void Main() { n = read(); m = read(); rep(i, 1, n) a[i] = read(); SGMT_tree :: build(1, 1, n); } } namespace SOLVE { void Main() { rep(i, 1, m) { int opt = read(); if(opt == 1) { int l = read(), r = read(), x = read(); SGMT_tree :: modify(1, 1, n, l, r, x); } if(opt == 2) { int l = read(), r = read(); SGMT_tree :: modify(1, 1, n, l, r); } if(opt == 3) { int l = read(), r = read(); write(SGMT_tree :: query(1, 1, n, l, r)), putchar('\n'); } } } } int main() { #ifdef Qrsikno freopen("uoj228.in", "r", stdin); freopen("uoj228.out", "w", stdout); #endif INIT :: Main(); SOLVE :: Main(); #ifdef Qrsikno debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC); #endif return IO.flush(); }