一个ACMer萌新 Happier233~
题目简述:
有n个字符串,每次字符串是一个数字
有两种操作:
- 区间查询:查询区间和,每次修改区间
- 区间修改:修改第i个节点的时候,节点原来的值为a[i],修改的值为d,则修改后的值为d a[i] d,例如原来的是321123,修改的值为4,则修改后为43211234
题目思路:
第一感觉就是用线段树维护区间和,但怎么去修改一个区间的值就成为了问题。
线段树每个节点维护2个值:
- sum1(l, r)= ∑ i = l r 1 0 len(a[i]) \sum_{i=l}^r10^\text{len(a[i])} ∑i=lr10len(a[i])
- sum2(l, r)= ∑ i = l r a[i] \sum_{i=l}^r\text{a[i]} ∑i=lra[i]
每次更新节点,这个节点的sum1和sum2修改如下:
- sum1=sum1*10+sum2*d+d*(r-l+1)
- sum2=sum2*100
由于数据量大,所以需要懒惰标记维护,一共需要维护三个标记:
- laz1维护右侧更新的值
- laz2维护左侧更新的值
- 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;
}