1. 程式人生 > 其它 >LG 題解 CF453E Little Pony and Lord Tirek

LG 題解 CF453E Little Pony and Lord Tirek

真正的危機不是機器人像人一樣思考,而是人像機器一樣思考。 目錄

前置芝士

  • 主席樹
  • 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;
}