题意:
对于长度为250000的区间,给了你四种操作:
操作A,从st到ed这段区间内的数,分别加上1,2,…,st-ed+1。
操作B,从st到ed这段区间内的数,分别加上,st-ed+1,st-ed,…,1。
操作C,将st到ed这段区间内的数赋值成x。
操作S,查询st到ed的这段区间内的数的总和。
解析:
因为操作A和操作B都是操作的实际上都是等差数列,所以可以一起考虑。
对于操作AB,在线段树的结点中记录了这个区间的首项a1,同时记录了这段区间内的公差d。
对于操作C,在线段树的结点内,用一个cover表示当前区间内的数是否全部相同,并且还用一个val表示如果在区间里的数完全相同的时候,即cover=1时,这个数是多少。容易得到,等差数列相加还是等差数列,所以可以对一个区间进行多次的AB操作。
对于C操作,因为强制将区间内的赋值成x,所以之前的AB操作全部失效,即这时候应该把表示AB操作的几个变量,a1和d全部赋值为零。
当向子区间传递记录的值的时候,应该优先C操作的标记,因为当操作AB和操作C的标记同时存在的时候,一定是发生在先进行了操作C,再进行了操作AB。
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
typedef long long ll;
const int N = 250001;
struct Node {
int L, R;
ll a1, d, val, sum;
bool cover;
Node() { a1 = d = val = sum = cover = 0;}
ll length() { return R - L + 1; }
} node[N<<2];
void pushUp(int o) {
node[o].sum = node[ls].sum + node[rs].sum;
}
void pushDown(int o) {
if(node[o].cover) {
node[ls].cover = node[rs].cover = true;
node[ls].val = node[rs].val = node[o].val;
node[ls].sum = node[ls].length() * node[o].val;
node[rs].sum = node[rs].length() * node[o].val;
node[ls].a1 = node[ls].d = node[rs].a1 = node[rs].d = 0;
node[o].val = node[o].cover = 0;
}
if(node[o].a1 || node[o].d) {
ll d = node[o].d;
ll len1 = node[ls].length(), len2 = node[rs].length();
ll a1 = node[o].a1, a2 = a1 + len1 * d;
node[ls].a1 += a1;
node[ls].d += d;
node[ls].sum += a1 * len1 + len1 * (len1-1)/2 * d;
node[rs].a1 += a2;
node[rs].d += d;
node[rs].sum += a2 * len2 + len2 * (len2-1)/2 * d;
node[o].a1 = node[o].d = 0;
}
}
void build(int o, int L, int R) {
node[o] = Node();
node[o].L = L, node[o].R = R;
if(L == R) return ;
int M = (L + R)/2;
build(lson);
build(rson);
pushUp(o);
}
void modify(int o, int L, int R, int ql, int qr, ll d) {
if(ql <= L && R <= qr) {
ll a1 = (d == 1) ? (L - ql + 1) : (qr - L + 1);
ll n = node[o].length();
node[o].a1 += a1;
node[o].d += d;
node[o].sum += a1 * n + n * (n-1)/2 * d;
return ;
}
pushDown(o);
int M = (L + R)/2;
if(ql <= M) modify(lson, ql, qr, d);
if(qr > M) modify(rson, ql, qr, d);
pushUp(o);
}
void setValue(int o, int L, int R, int ql, int qr, ll val) {
if(ql <= L && R <= qr) {
node[o].sum = node[o].length() * val;
node[o].val = val;
node[o].cover = true;
node[o].a1 = node[o].d = 0;
return ;
}
pushDown(o);
int M = (L + R)/2;
if(ql <= M) setValue(lson, ql, qr, val);
if(qr > M) setValue(rson, ql, qr, val);
pushUp(o);
}
ll query(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr)
return node[o].sum;
pushDown(o);
int M = (L + R)/2;
ll ret = 0;
if(ql <= M) ret += query(lson, ql, qr);
if(qr > M) ret += query(rson, ql, qr);
return ret;
}
int main() {
build(1, 1, N);
int T;
scanf("%d", &T);
char oper[5];
int ql, qr, val;
while(T--) {
scanf("%s%d%d", oper, &ql, &qr);
if(oper[0] == 'A') {
modify(1, 1, N, ql, qr, 1);
}else if(oper[0] == 'B') {
modify(1, 1, N, ql, qr, -1);
}else if(oper[0] == 'C') {
scanf("%d", &val);
setValue(1, 1, N, ql, qr, val);
}else if(oper[0] == 'S') {
printf("%lld\n", query(1, 1, N, ql, qr));
}
}
return 0;
}
本文介绍了一种使用线段树解决区间更新和查询问题的方法,包括加法更新、等差数列更新及区间赋值操作。通过维护区间首项、公差、覆盖标志等属性实现高效处理。

2577

被折叠的 条评论
为什么被折叠?



