LG 題解 CF453E Little Pony and Lord Tirek
阿新 • • 發佈:2021-08-04
真正的危機不是機器人像人一樣思考,而是人像機器一樣思考。
目錄
級別的。
前置芝士
- 主席樹
- STL-set
Description
你有 \(n\) 匹小馬,分別標號 \(1 \sim n\),每個小馬有三個屬性 \(s_i, m_i, r_i\) 分別表示初始魔力,最大魔力,單位時間增加的魔力。然後有 \(m\) 次詢問,每次詢問給你三個值 \(t, l, r\) 表示在 \(t\) 時間吸取 \([l,r]\) 區間內的小馬,輸出每次吸取的魔力。
Solution
考慮顏色段均攤的做法,用一個 set 維護被更改的時間相同的顏色段。
由於只有區間賦值操作,且查詢後立即賦值,所以每個顏色段只會對後面的一次查詢產生影響。而且每次賦值只會增加 1 個顏色段,所以總的顏色段數量是 \(O(m)\)
我們對整體建立兩顆可持久化線段樹(主席樹),一棵在 \(\frac{m_i}{r_i}\) 處維護 \(r_i\),另一顆在 \(\frac{m_i}{r_i}\) 處維護 \(m_i\) 的和。
對於一個 \((t,l,r)\) 的詢問,將 \([l,r]\) 通過 set 中的顏色段分成一段一段的區間,每個區間內被修改的時間都是相同的。
- 如果這個區間以前沒被修改,說明有初值,我們暴力修改;
- 否則,設這個區間上次修改時間為 \(t_0\),此時初值已經沒有影響了。當小馬的 \(\frac{m_i}{r_i} < t - t_0\) 時,答案會加上 \(m_i\);否則答案會加上 \((t - t_0)r_i\)
對於 set 的細節,可以按照維護一個結構體,標記左右端點,是否是第一次覆蓋和上一次覆蓋的時間,然後維護整個區間,查詢後就刪掉,用新的區間覆蓋。反正細節巨大多,具體看程式碼吧。
時間複雜度 \(O((n+m) \log n)\)。
Code
/* Work by: Suzt_ilymics Problem: 不知名屑題 Knowledge: 垃圾演算法 Time: O(能過) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<set> #define int long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 2e5+5; const int INF = 1e9+7; const int mod = 1e9+7; const int Max = 1e6; struct node { int l, r, tag, tim; bool operator < (const node &b) const { return l < b.l; } }; int n, m, Ans = 0; int fir[MAXN], lim[MAXN], r[MAXN]; int root_r[MAXN], root_m[MAXN]; set<node> s; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } namespace Hjt { #define ls lson[now_] #define rs rson[now_] int lson[MAXN << 5], rson[MAXN << 5], siz[MAXN << 5], val[MAXN << 5], node_num = 0; void Modify(int &now_, int pre_, int l, int r, int pos, int val_) { now_ = ++ node_num; lson[now_] = lson[pre_], rson[now_] = rson[pre_]; val[now_] = val[pre_] + val_; if(l == r) return ; int mid = (l + r) >> 1; if(mid >= pos) Modify(ls, lson[pre_], l, mid, pos, val_); else Modify(rs, rson[pre_], mid + 1, r, pos, val_); } int Query(int now_, int pre_, int l, int r, int L, int R) { if(L <= l && r <= R) return val[now_] - val[pre_]; if(l == r) return 0; int mid = (l + r) >> 1, ans = 0; if(mid >= L) ans += Query(ls, lson[pre_], l, mid, L, R); if(mid < R) ans += Query(rs, rson[pre_], mid + 1, r, L, R); return ans; } } int BL(const node &it, int t) { int res = 0; t -= it.tim; for(int i = it.l; i <= it.r; ++i) { res += min(lim[i], fir[i] + r[i] * t); fir[i] = 0; } return res; } int Qry(const node &it, int t) { if(it.tag) return BL(it, t); t -= it.tim; return Hjt::Query(root_m[it.r], root_m[it.l - 1], 0, Max, 0, t - 1) + t * Hjt::Query(root_r[it.r], root_r[it.l - 1], 0, Max, t, Max); } signed main() { // freopen("CF453E.in","r",stdin); // freopen("test.out","w",stdout); n = read(); for(int i = 1; i <= n; ++i) { fir[i] = read(), lim[i] = read(), r[i] = read(); if(!r[i]) { Hjt::Modify(root_r[i], root_r[i - 1], 0, Max, 0, 0); Hjt::Modify(root_m[i], root_m[i - 1], 0, Max, 0, 0); } else { Hjt::Modify(root_r[i], root_r[i - 1], 0, Max, lim[i] / r[i], r[i]); Hjt::Modify(root_m[i], root_m[i - 1], 0, Max, lim[i] / r[i], lim[i]); } } m = read(); s.insert((node){1, n, 1, 0}); for(int i = 1, t, l, r; i <= m; ++i) { t = read(), l = read(), r = read(), Ans = 0; set<node>::iterator it1 = --s.upper_bound((node){l, 0, 0, 0}),it2 = --s.upper_bound((node){r, 0, 0, 0}); if(it1 == it2) { Ans += Qry((node){l, r, it1->tag, it1->tim}, t); node is = *it1; s.erase(it1); if(l != is.l) s.insert((node){is.l, l - 1, is.tag, is.tim}); s.insert((node){l, r, 0, t}); if(r != is.r) s.insert((node){r + 1, is.r, is.tag, is.tim}); } else { Ans += Qry((node){l, it1->r, it1->tag, it1->tim}, t); node is1 = *it1, is2 = *it2; for(set<node>::iterator it = s.erase(it1); it != it2 && it != s.end(); it = s.erase(it)) { Ans += Qry(*it, t); } Ans += Qry((node){it2->l, r, it2->tag, it2->tim}, t); s.erase(it2); if(is1.l <= l - 1) s.insert((node){is1.l, l - 1, is1.tag, is1.tim}); if(is2.r >= r + 1) s.insert((node){r + 1, is2.r, is2.tag, is2.tim}); s.insert((node){l, r, 0, t}); } printf("%lld\n", Ans); } return 0; }