LOJ传送门
题目描述
有一个长度为 n n n 的序列,要求支持三种操作:
1 l r x
将 [ l , r ] [l, r] [l,r] 中的数增加 x x x,保证 x ≤ 10000 x \leq 10000 x≤10000;2 l r x
用 [ l , l + x ] [l, l + x] [l,l+x]中的数对应替换 $[r, r + x] $中的数;3 l r
求 [ l , r ] [l, r] [l,r] 中所有数的和。
输入输出格式
输入格式
第一行两个正整数
n
,
m
n, m
n,m表示序列长度和操作数。
第二行 $n $个正整数表示初始序列中的数,保证每个数
≤
10000
\leq 10000
≤10000。
接下来
m
m
m 行,每行三或四个整数,对应一个操作。
保证操作的区间合法且为
[
1
,
n
]
[1, n]
[1,n] 的子集。
输出格式
对每个操作三,单独输出一行表示答案。
输入输出样例
输入样例#1:
4 4
1 2 3 4
1 2 3 4
3 1 4
2 1 3 1
3 2 4
输出样例#1:
18
13
数据范围与提示
n ≤ 100000 , m ≤ 100000 n \leq 100000, m \leq 100000 n≤100000,m≤100000
解题分析
区间替换这个操作, 一开始没什么头绪, 想了一会发现: 诶这不就和平衡树的插入差不多吗, 把原来一截 e r a s e erase erase掉然后 i n s e r t insert insert一截新的。 只不过这段新的是原来序列的一部分, 那就可持久化一下就好了。
跟 R o c k d u Rockdu Rockdu大佬学了一下 f h q T r e a p fhqTreap fhqTreap不记 k e y key key值的写法, 因为实在卡空间…
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define gc getchar()
#define MX 100500
#define ll long long
template <class T>
IN void in(T &x)
{
static char c; static bool neg;
x = 0; c = gc;
for (; !isdigit(c); c = gc)
if (c == '-') neg = true;
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
if (neg) neg = false, x = -x;
}
int cnt, n, m, root;
struct Node {int son[2], val, siz, tag; ll sum;} tree[MX * 350];
IN int rd() {return (1ll * rand() * rand() % INT_MAX + rand()) % INT_MAX;}
IN void pushup(R int now)
{
tree[now].siz = tree[ls].siz + tree[rs].siz + 1;
tree[now].sum = tree[ls].sum + tree[rs].sum + tree[now].val;
}
IN void pushdown(R int now)
{
if (tree[now].tag)
{
if (ls)
{
tree[++cnt] = tree[ls], ls = cnt;
tree[ls].tag += tree[now].tag;
tree[ls].sum += 1ll * tree[now].tag * tree[ls].siz;
tree[ls].val += tree[now].tag;
}
if (rs)
{
tree[++cnt] = tree[rs], rs = cnt;
tree[rs].tag += tree[now].tag;
tree[rs].sum += 1ll * tree[now].tag * tree[rs].siz;
tree[rs].val += tree[now].tag;
}
tree[now].tag = 0;
}
}
void split(R int now, R int tar, int &x, int &y)
{
if (!now) return x = y = 0, void();
pushdown(now);
if (tree[ls].siz >= tar)
{
tree[y = ++cnt] = tree[now];
split(ls, tar, x, tree[y].son[0]);
pushup(y);
}
else
{
tree[x = ++cnt] = tree[now];
split(rs, tar - tree[ls].siz - 1, tree[x].son[1], y);
pushup(x);
}
}
int Merge(R int x, R int y)//normal, when inserting
{
if ((!x) || (!y)) return x | y;
if (rd() % (tree[x].siz + tree[y].siz) < tree[x].siz)
{
pushdown(x);
tree[x].son[1] = Merge(tree[x].son[1], y);
pushup(x); return x;
}
else
{
pushdown(y);
tree[y].son[0] = Merge(x, tree[y].son[0]);
pushup(y); return y;
}
}
int merge(R int x, R int y)
{
if ((!x) || (!y)) return x | y;
if (rd() % (tree[x].siz + tree[y].siz) < tree[x].siz)
{
pushdown(x);
tree[++cnt] = tree[x], x = cnt;
tree[x].son[1] = merge(tree[x].son[1], y);
pushup(x); return x;
}
else
{
pushdown(y);
tree[++cnt] = tree[y], y = cnt;
tree[y].son[0] = merge(x, tree[y].son[0]);
pushup(y); return y;
}
}
IN void query(R int lef, R int rig)
{
R int x, y, z;
split(root, rig, x, z);
split(x, lef - 1, x, y);
printf("%lld\n", tree[y].sum);
}
IN void add(R int lef, R int rig, R int tg)
{
R int x, y, z;
split(root, rig, x, z);
split(x, lef - 1, x, y);
tree[y].tag += tg;
tree[y].sum += tree[y].siz * tg;
tree[y].val += tg;
root = Merge(Merge(x, y), z);
}
IN void modify(R int from, R int to, R int len)
{
int x, y, z, p, q, w;
split(root, from + len, x, z);
split(x, from - 1, x, y);
split(root, to + len, p, w);
split(p, to - 1, p, q);
root = merge(merge(p, y), w);
}
int main(void)
{
int typ, l, r, x;
srand(time(NULL));
in(n), in(m);
for (R int i = 1; i <= n; ++i)
{
in(x);
tree[++cnt] = {{0, 0}, x, 1, 0, x};
root = Merge(root, cnt);
}
W (m--)
{
in(typ);
switch(typ)
{
case 1: in(l), in(r), in(x), add(l, r, x); break;
case 2: in(l), in(r), in(x), modify(l, r, x); break;
case 3: in(l), in(r), query(l, r); break;
}
}
}