1 条题解

  • 0
    @ 2025-8-24 22:39:44

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar liheyang123
    「假装不在意,直到真的不在意」

    搬运于2025-08-24 22:39:44,当前版本为作者最后更新于2025-08-19 21:45:04,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    solution

    先考虑特殊的,假设每一组询问 (L,R)(L,R),满足 L=1L = 1 那么问题简化为依次执行操作序列的第 1,2,,R1,2,\cdots,R 项所对应的操作,此时答案为 i=1mCi\sum^{m}_{i=1}C_i

    但是对于询问 (L,R)(L,R),不能直接用 (1,R)(1,R)(1,L1)(1,L-1) 对应的答案相见,因为可能会覆盖之前的操作,此处应该可以想到 ODT,离线,将询问挂在 r 上扫描线,对于一段,其操作序列中的顺序是第 tt 个,权值为 vv,区间长度为 ll,对于 tt 如果被覆盖,其对后续的贡献为 l×v-l\times v,记 tt 的对当前贡献为 ata_t,那么显然答案是 i=Lnai\sum^{n}_{i=L}a_i

    时间复杂度分析

    ODT O(nlogn)O(n\log n),询问总共需要 O(nlogn)O(n\log n)n,m,qn, m, q 同阶,此处不区分。

    code

    感觉代码整体很板。 ::::info[使用了AI工具提升代码可读性]

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define int ll
    
    namespace FastIO {
        const int BUFFER_SIZE = 1 << 20;
        char inbuf[BUFFER_SIZE], outbuf[BUFFER_SIZE];
        char *pin = inbuf, *pin_end = inbuf;
        int outpos = 0;
        
        inline char getchar() {
            if (pin == pin_end) {
                pin = inbuf;
                pin_end = inbuf + fread(inbuf, 1, BUFFER_SIZE, stdin);
                if (pin == pin_end) return EOF;
            }
            return *pin++;
        }
        
        template <typename T>
        inline T read() {
            T x = 0, f = 1;
            char ch = getchar();
            while (ch < '0' || ch > '9') {
                if (ch == '-') f = -1;
                ch = getchar();
            }
            while (ch >= '0' && ch <= '9') {
                x = (x << 1) + (x << 3) + (ch - '0');
                ch = getchar();
            }
            return x * f;
        }
        
        template <typename T>
        inline void write(T x, char end_char = '\n') {
            if (outpos >= BUFFER_SIZE - 32) {
                fwrite(outbuf, 1, outpos, stdout);
                outpos = 0;
            }
            if (x < 0) {
                outbuf[outpos++] = '-';
                x = -x;
            }
            char temp[64];
            int len = 0;
            do {
                temp[len++] = x % 10 + '0';
                x /= 10;
            } while (x);
            while (len--) {
                outbuf[outpos++] = temp[len];
            }
            outbuf[outpos++] = end_char;
        }
        
        inline void flush() {
            if (outpos) {
                fwrite(outbuf, 1, outpos, stdout);
                outpos = 0;
            }
        }
    } using namespace FastIO;
    
    const int MAX_N = 5e5 + 10;
    
    // 线段信息结构体
    struct Segment {
        int left, right;    // 线段左右端点
        int timestamp;      // 时间戳(赋值时间)
        int value;          // 线段的值
        
        Segment() : left(0), right(0), timestamp(0), value(0) {}
        Segment(int l, int r, int t, int v) : left(l), right(r), timestamp(t), value(v) {}
        
        // 按左端点排序
        bool operator < (const Segment &other) const {
            if (left != other.left) return left < other.left;
            if (right != other.right) return right < other.right;
            if (timestamp != other.timestamp) return timestamp < other.timestamp;
            return value < other.value;
        }
    };
    
    // 查询结构体
    struct QueryInfo {
        int left_bound;     // 查询左边界
        int query_id;       // 查询ID
        
        QueryInfo(int l, int id) : left_bound(l), query_id(id) {}
    };
    
    int n, m, q;
    int segment_left[MAX_N], segment_right[MAX_N], segment_value[MAX_N];
    int answer[MAX_N];
    vector<QueryInfo> queries_by_right[MAX_N];
    
    // 珂朵莉树(ODT)
    set<Segment> odt_set;
    
    // 树状数组(用于区间查询)
    int fenwick_tree[MAX_N];
    
    // 树状数组:单点更新
    void update_fenwick(int position, int delta) {
        for (; position > 0; position -= position & -position) {
            fenwick_tree[position] += delta;
        }
    }
    
    // 树状数组:前缀和查询
    int query_fenwick(int position) {
        int result = 0;
        for (; position <= n; position += position & -position) {
            result += fenwick_tree[position];
        }
        return result;
    }
    
    // ODT核心操作:在指定位置分割线段
    set<Segment>::iterator split_odt(int split_position) {
        auto iter = odt_set.lower_bound(Segment(split_position, 0, 0, 0));
        if (iter != odt_set.end() && iter->left == split_position) {
            return iter;
        }
        
        iter--;
        Segment original_segment = *iter;
        odt_set.erase(iter);
        
        // 分割为两个线段
        odt_set.insert(Segment(original_segment.left, split_position - 1, 
                             original_segment.timestamp, original_segment.value));
        
        auto result = odt_set.insert(Segment(split_position, original_segment.right,
                                          original_segment.timestamp, original_segment.value));
        return result.first;
    }
    
    // ODT核心操作:区间赋值
    void assign_odt(int assign_left, int assign_right, int timestamp, int value) {
        // 分割出操作区间
        auto right_iter = split_odt(assign_right + 1);
        auto left_iter = split_odt(assign_left);
        
        // 删除原有线段的影响
        for (auto iter = left_iter; iter != right_iter; ++iter) {
            const Segment &seg = *iter;
            int segment_length = seg.right - seg.left + 1;
            update_fenwick(seg.timestamp, -segment_length * seg.value);
        }
        
        // 删除旧线段,插入新线段
        odt_set.erase(left_iter, right_iter);
        int new_length = assign_right - assign_left + 1;
        update_fenwick(timestamp, new_length * value);
        odt_set.insert(Segment(assign_left, assign_right, timestamp, value));
    }
    
    signed main() {
        // 读取输入
        n = read<int>(), m = read<int>(), q = read<int>();
        
        for (int i = 1; i <= n; i++) {
            segment_left[i] = read<int>();
            segment_right[i] = read<int>();
            segment_value[i] = read<int>();
        }
        
        // 存储查询
        for (int i = 1; i <= q; i++) {
            int query_left = read<int>(), query_right = read<int>();
            queries_by_right[query_right].emplace_back(query_left, i);
        }
        
        // 初始化ODT:整个区间初始值为0,时间戳为1
        odt_set.insert(Segment(1, m, 1, 0));
        
        // 处理每个时间点的操作
        for (int current_time = 1; current_time <= n; current_time++) {
            // 执行区间赋值操作
            assign_odt(segment_left[current_time], segment_right[current_time], 
                      current_time, segment_value[current_time]);
            
            // 处理当前时间点的所有查询
            for (const auto &query_info : queries_by_right[current_time]) {
                int prefix_sum = query_fenwick(query_info.left_bound);
                answer[query_info.query_id] = prefix_sum;
            }
        }
        
        // 输出所有查询结果
        for (int i = 1; i <= q; i++) {
            write(answer[i]);
        }
        
        flush();
        return 0;
    }
    

    ::::

    • 1

    信息

    ID
    8030
    时间
    2500ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者