zoukankan      html  css  js  c++  java
  • 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
    ", Ans);
        }
        return 0;
    }
    
  • 相关阅读:
    AtCoder Beginner Contest 113 D Number of Amidakuji
    UVA
    mt19937 -- 高质量随机数
    牛客网NOIP赛前集训营-提高组(第七场)C 洞穴
    牛客OI周赛4-提高组 C 战争(war)
    牛客OI周赛4-提高组 B 最后的晚餐(dinner)
    bzoj 4318 || 洛谷P1654 OSU!
    Tourists Codeforces
    bzoj 1791 [Ioi2008]Island 岛屿
    洛谷 P2231 [HNOI2002]跳蚤
  • 原文地址:https://www.cnblogs.com/Silymtics/p/solution-CF453E.html
Copyright © 2011-2022 走看看