HDU-6562 Lovers 2018CCPC-吉林(线段树)

本文介绍了一道HDU6562竞赛题目的解题思路与实现细节,利用线段树维护区间和,并通过懒惰标记优化大规模数据处理,实现了区间查询和修改的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接 - HDU 6562

一个ACMer萌新 Happier233~

题目简述:

有n个字符串,每次字符串是一个数字
有两种操作:

  1. 区间查询:查询区间和,每次修改区间
  2. 区间修改:修改第i个节点的时候,节点原来的值为a[i],修改的值为d,则修改后的值为d a[i] d,例如原来的是321123,修改的值为4,则修改后为43211234

题目思路:

第一感觉就是用线段树维护区间和,但怎么去修改一个区间的值就成为了问题。
线段树每个节点维护2个值:

  1. sum1(l, r)= ∑ i = l r 1 0 len(a[i]) \sum_{i=l}^r10^\text{len(a[i])} i=lr10len(a[i])
  2. sum2(l, r)= ∑ i = l r a[i] \sum_{i=l}^r\text{a[i]} i=lra[i]

每次更新节点,这个节点的sum1和sum2修改如下:

  1. sum1=sum1*10+sum2*d+d*(r-l+1)
  2. sum2=sum2*100

由于数据量大,所以需要懒惰标记维护,一共需要维护三个标记:

  1. laz1维护右侧更新的值
  2. laz2维护左侧更新的值
  3. laz3维护长度的变化

具体懒惰标记的修改见代码

最后还要膜一下tokitsukaze大佬,常数优化tql,我也想学?
在这里插入图片描述

代码:

// 巨菜的ACMer-Happier233

#include <bits/stdc++.h>

using namespace std;

//-----
typedef double db;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define fi first
#define se second
#define pw(x) (1ll << (x))
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define rep(i, l, r) for(int i=(l);i<(r);++i)
#define per(i, l, r) for(int i=(r)-1;i>=(l);--i)
#define sf(x) scanf("%d", &(x))

#define foreg(i, s, eg) for(int i = (s); ~i; i = (eg)[i].nxt)

const double pi = acos(-1);
const ll MOD = ll(1e9 + 7);

const int N = int(2e5 + 10);
const int M = int(2e5 + 10);

ll powm(ll a, ll k) {
    ll c = 1;
    for (; k; k >>= 1) {
        if (k & 1) (c *= a) %= MOD;
        (a *= a) %= MOD;
    }
    return c;
}

struct TreeNode {
    int l, r;
    int lson, rson;
    ll sum;
    ll len;
    ll laz1, laz2, laz3;

    inline void init(int a, int b, int ls, int rs) {
        lson = ls;
        rson = rs;
        l = a, r = b;
        sum = 0;
        len = 1;
        laz1 = laz2 = 0;
        laz3 = 1;
    }

    inline int mid() {
        return (l + r) >> 1;
    }

    inline int width() {
        return r - l + 1;
    }

    inline void add(ll val) {
        sum = (sum * 10 + val * len * 10 + val * width()) % MOD;
        len = (len * 100) % MOD;
        // 右懒惰
        laz1 = (laz1 * 10 + val) % MOD;
        // 左懒惰
        laz2 = (laz2 + val * laz3) % MOD;
        // 长度懒惰
        laz3 = (laz3 * 10) % MOD;
    }
};

struct SegTree {
    int tot;
    TreeNode node[N << 1];

    inline void init() {
        tot = 0;
    }

    inline void up(int k) {
        TreeNode &nd = node[k];
        nd.sum = (node[nd.lson].sum + node[nd.rson].sum) % MOD;
        nd.len = (node[nd.lson].len + node[nd.rson].len) % MOD;
    }

    inline void push(int k) {
        TreeNode &nd = node[k];
        if (nd.laz3 == 1) return;
        TreeNode &lson = node[nd.lson];
        TreeNode &rson = node[nd.rson];

        lson.sum = (nd.laz1 * lson.width() + lson.sum * nd.laz3 + nd.laz2 * lson.len % MOD * nd.laz3) % MOD;
        lson.len = (lson.len * nd.laz3 % MOD * nd.laz3) % MOD;
        lson.laz1 = (lson.laz1 * nd.laz3 + nd.laz1) % MOD;
        lson.laz2 = (nd.laz2 * lson.laz3 + lson.laz2) % MOD;
        lson.laz3 = (lson.laz3 * nd.laz3) % MOD;

        rson.sum = (nd.laz1 * rson.width() + rson.sum * nd.laz3 + nd.laz2 * rson.len % MOD * nd.laz3) % MOD;
        rson.len = (rson.len * nd.laz3 % MOD * nd.laz3) % MOD;
        rson.laz1 = (rson.laz1 * nd.laz3 + nd.laz1) % MOD;
        rson.laz2 = (nd.laz2 * rson.laz3 + rson.laz2) % MOD;
        rson.laz3 = (rson.laz3 * nd.laz3) % MOD;

        nd.laz1 = nd.laz2 = 0;
        nd.laz3 = 1;
    }

    void build(int k, int l, int r) {
        TreeNode &nd = node[k];
        nd.init(l, r, tot + 1, tot + 2);
        tot += 2;
        if (l == r) {
            return;
        }
        int mid = nd.mid();
        build(nd.lson, nd.l, mid);
        build(nd.rson, mid + 1, nd.r);
        up(k);
    }

    void change(int k, int l, int r, ll val) {

        TreeNode &nd = node[k];
        if (nd.l == l && nd.r == r) {
            nd.add(val);
            return;
        }
        push(k);
        int mid = nd.mid();
        if (r <= mid) {
            change(nd.lson, l, r, val);
        } else if (l > mid) {
            change(nd.rson, l, r, val);
        } else {
            change(nd.lson, l, mid, val);
            change(nd.rson, mid + 1, r, val);
        }
        up(k);
    }

    ll query(int k, int l, int r) {
        TreeNode &nd = node[k];
        if (nd.l == l && nd.r == r) {
            return nd.sum;
        }
        push(k);
        int mid = nd.mid();
        ll ans = 0;
        if (r <= mid) {
            ans += query(nd.lson, l, r);
        } else if (l > mid) {
            ans += query(nd.rson, l, r);
        } else {
            ans += query(nd.lson, l, mid);
            ans += query(nd.rson, mid + 1, r);
        }
        return ans % MOD;
    }
} tree;

int TC = 0;

void solve() {
    printf("Case %d:\n", ++TC);
    int n, q;
    cin >> n >> q;
    tree.init();
    tree.build(0, 1, n);
    string str;
    while (q--) {
        int l, r, d;
        cin >> str >> l >> r;
        if (str == "wrap") {
            cin >> d;
            tree.change(0, l, r, d);
        } else {
            ll ans = tree.query(0, l, r) % MOD;
            printf("%lld\n", ans);
        }
    }
}

int main() {
#ifdef ACM_LOCAL
    freopen("./data/std.in", "r", stdin);
    // freopen("./data/std.out", "w", stdout);
#else
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#endif
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值