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;
}