【线段树】【数据结构】Data Structure Special Training 2 T1 setmod 题解

Problem 1. setmod
Input file: setmod.in
Output file: setmod.out
Time limit: 2 seconds
Memory limit: 256 MB
给你一个序列:a1 a2 a3 : : : an,有m 个操作,操作如下:
• modify l r x  将区间[l; r] 中的每个数修改为x
• change l r x 将区间[l; r] 中的每个数加上x
• query l r 询问区间[l; r] 中的和
Input
第1 行2 个整数:n m,表示序列长的和操作数.
第2 行n 个整数:a1 a2 a3 : : : an,表示初始序列.
接下来m 行,每行是上面三种操作中的一种.
Output
对于每个询问操作,输出其结果.
Sample
setmod.in setmod.out
3 3
1 2 3
change 1 3 2
modify 3 3 3
query 1 3
10
Note
• 对于30% 的数据,1 n;m 103
• 对于100% 的数据,1 n;m 105,1 ai; x n,1 l r n
Page 1

PS
神奇的数据有 r > l 的数据,当 r > l 时不处理,询问输出0

Hint
普通线段树,打俩lazy标记,modify可以覆盖change

题解
1.1 30%
O(nm) 暴力。
1.2 100%
要维护几个东西:
• sum 表示区间的和
• type 表示现在的标记类型(可以是没有标记,可以是增量标记,可以是
赋值标记)
• delta 如果是增量标记,那么这个里面存的增量
• value 如果是赋值标记,那么这里面就存的是那个值
然后就秩序要讨论一下发现:
• 空标记+ 赋值操作= 赋值标记
• 空标记+ 增量操作= 增量标记
• 增量标记+ 赋值操作= 赋值标记
• 增量标记+ 增量操作= 增量标记
• 赋值标记+ 增量操作= 赋值标记
• 赋值标记+ 赋值操作= 赋值标记
因为它们之间能和谐共处(如果A 标记遇见B 操作无法转化为一种现有的标
记,那么他们就不能同时用线段树实现),所以就能完成两种操作同时进行。具
体看代码是怎样合并的。

#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<fstream>
#include<sstream>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define llf (1LL << 60)
using namespace std;

template <class T> inline void read(T &x) {
    int flag = 1; x = 0;
    char ch = getchar();
    while(ch <  '0' || ch >  '9') { if(ch == '-')  flag = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = (x<<1)+(x<<3)+ch-'0'; ch = getchar(); }
    x *= flag;
}

inline char Read() {
    char ch = getchar();
    while(ch == ' ' || ch == '\n') ch = getchar();
    return ch;
}

typedef struct SegTreeNode {
    public:
        long long val;
        SegTreeNode *l, *r;
        long long clazy;
        long long mlazy;
        SegTreeNode(int val = 0, SegTreeNode* l = NULL, SegTreeNode* r = NULL, long long mlazy = llf, long long clazy = 0):val(val), l(l), r(r), mlazy(mlazy), clazy(clazy) {       }

        inline void pushUp() {
            this->val = l->val + r->val;
        }

        inline void pushmDown(int le, int ri, int mid) {
            l->val = (mid - le + 1) * mlazy;
            r->val = (ri - mid) * mlazy;
            l->mlazy = r->mlazy = mlazy;
            l->clazy = r->clazy = 0;
            mlazy = llf;
        }

        inline void pushcDown(int le, int ri, int mid) {
            l->val += (mid - le + 1) * clazy;
            r->val += (ri - mid) * clazy;
            l->clazy += clazy, r->clazy += clazy;
            clazy = 0;
        }
}SegTreeNode;

typedef struct SegTree {
    public:
        SegTreeNode* root;

        SegTree():root(NULL) {      }
        SegTree(int s, int* lis) {
            build(root, 1, s, lis);
        }

        void build(SegTreeNode*& node, int l, int r, int* lis) {
            node = new SegTreeNode();
            if(l == r) {
                node->val = lis[l];
                return;
            }
            int mid = (l + r) >> 1;
            build(node->l, l, mid, lis);
            build(node->r, mid + 1, r, lis);
            node->pushUp();
        }

        void modify(SegTreeNode*& node, int l, int r, int ml, int mr, int x) {
            if(l == ml && r == mr) {
                node->val = (r - l + 1) * 1LL * x;
                node->mlazy = x, node->clazy = 0;
                return;
            }
            int mid = (l + r) >> 1;
            if(node->mlazy != llf) node->pushmDown(l, r, mid);
            if(node->clazy) node->pushcDown(l, r, mid);
            if(mr <= mid) modify(node->l, l, mid, ml, mr, x);
            else if(ml > mid) modify(node->r, mid + 1, r, ml, mr, x);
            else {
                modify(node->l, l, mid, ml, mid, x);
                modify(node->r, mid + 1, r, mid + 1, mr, x);
            }
            node->pushUp();
        }

        void update(SegTreeNode*& node, int l, int r, int ml, int mr, int x) {
            if(l == ml && r == mr) {
                node->val += (r - l + 1) * 1LL * x;
                node->clazy += x;
                return;
            }
            int mid = (l + r) >> 1;
            if(node->mlazy != llf) node->pushmDown(l, r, mid);
            if(node->clazy) node->pushcDown(l, r, mid);
            if(mr <= mid)   update(node->l, l, mid, ml, mr, x);
            else if(ml > mid)   update(node->r, mid + 1, r, ml, mr, x);
            else {
                update(node->l, l, mid, ml, mid, x);
                update(node->r, mid + 1, r, mid + 1, mr, x);
            }
            node->pushUp();
        }

        long long query(SegTreeNode*& node, int l, int r, int ql, int qr) {
            if(l == ql && r == qr) {
                return node->val;
            }
            int mid = (l + r) >> 1;
            if(node->mlazy != llf) node->pushmDown(l, r, mid);
            if(node->clazy) node->pushcDown(l, r, mid);
            if(qr <= mid)   return query(node->l, l, mid, ql, qr);
            if(ql > mid)    return query(node->r, mid + 1, r, ql, qr);
            return query(node->l, l, mid, ql, mid) + query(node->r, mid + 1, r, mid + 1, qr);
        }
}SegTree;

int n, m;
int* lis;
SegTree st;

inline void init() {
    read(n);
    read(m);
    lis = new int[(const int)(n + 1)];
    for(int i = 1; i <= n; i++) read(lis[i]);
    st = SegTree(n, lis);
}

char s[11];
inline void solve() {
    int a, b, x;
    while(m--) {
        scanf("%s", s);
        read(a);
        read(b);
        if(s[0] == 'm') {
            read(x);
            if(b > a) continue;
            st.modify(st.root, 1, n, a, b, x);
        } else if(s[0] == 'c') {
            read(x);
            if(b > a) continue;
            st.update(st.root, 1, n, a, b, x);
        } else {
            if(b > a) {
                printf("0\n");
                continue;
            }
            long long res = st.query(st.root, 1, n, a, b);
            cout << res << endl;
        }
    }
}

int main() {
    freopen("setmod.in", "r", stdin);
    freopen("setmod.out", "w", stdout);
    init();
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值