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;
}
posted @ 2021-08-04 18:19  Suzt_ilymtics  阅读(51)  评论(0编辑  收藏  举报