Description
给出一个N个整数构成的序列,有M次操作,每次操作有一下三种:
①Insert Y X,在序列的第Y个数之前插入一个数X;
②Add L R X,对序列中第L个数到第R个数,每个数都加上X;
③Query L R,询问序列中第L个数到第R个数的平方和。
Input
第一行一个正整数N,表示初始序列长度。
第二行N个整数Ai,表示初始序列中的数。
第三行一个正整数M,表示操作数。
接下来M行,每行一种操作。
Output
对于每一个Query操作输出答案。由于答案可能很大,请mod 7459后输出。
Sample Input
5
1 2 3 4 5
5
Query 1 3
Insert 2 5
Query 2 4
Add 5 6 7
Query 1 6
Sample Output
14
38
304
样例解释:
第二次操作后的序列:1,5,2,3,4,5。
第四次操作后的序列:1,5,2,3,11,12。
Data Constraint
30%的数据满足N≤1,000,M≤1,000。
另外20%的数据满足N≤100,000,M≤100,000,且不存在Insert操作。
100%的数据满足N≤100,000,M≤100,000,且Add和Insert操作中|X|≤1000,|Ai|≤1000。
题目大意:
给一个序列,每次可以区间加上一个数,还可以插入一个数,动态求某区间的平方和。
题解:
如果没有插入操作,相信只要对数学有点造诣的人,都会用线段树做。
把一个数a增加b,它的平方和会变成
(a+b)2−a2=2ab+b2
。
把一个区间加上b,那么我们只需要维护这个区间的个数,和,平方和,就可以求出新的平方和。
用splay维护也是一样的,插入时需要插入到第c个数旁,那么就在splay里找到一个点x,它和它的子树的大小是c-1,把x旋到根,再找到一个点y,它和它的子树的大小是c,把y旋到根的右边,那么在y的左节点新建一个点,就是要插入的点,再把它旋到根,至此就完成了。
Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define ll long long
#define mo 7459
using namespace std;
const int Maxn = 200100;
int n, m, fa[Maxn], t[Maxn][2], d[Maxn], td;
struct Point {
ll z, siz, sum, sqr, lz;
}a[Maxn];
void update(int x) {
a[x].siz = a[t[x][0]].siz + a[t[x][1]].siz + 1;
a[x].sum = a[t[x][0]].sum + a[t[x][1]].sum + a[x].z;
a[x].sqr = a[t[x][0]].sqr + a[t[x][1]].sqr + a[x].z * a[x].z;
}
int lr(int x) {return t[fa[x]][1] == x;}
void chan(int x, ll y) {
if(!x) return;
a[x].sqr += 2 * a[x].sum * y + a[x].siz * y * y;
a[x].sum += a[x].siz * y;
a[x].z += y;
a[x].lz += y;
}
void down(int x) {if(a[x].lz) chan(t[x][0], a[x].lz), chan(t[x][1], a[x].lz), a[x].lz = 0;}
void rotate(int x) {
int y = fa[x], k = lr(x);
t[y][k] = t[x][!k];
if(t[x][!k]) fa[t[x][!k]] = y;
fa[x] = fa[y];
if(fa[y]) t[fa[y]][lr(y)] = x;
t[x][!k] = y; fa[y] = x;
update(y); update(x);
}
void xc(int x) {
while(x) d[++ d[0]] = x, x = fa[x];
for(; d[0]; d[0] --) down(d[d[0]]);
}
void splay(int x, int y) {
xc(x);
while(fa[x] != y) {
if(fa[fa[x]] != y)
if(lr(x) == lr(fa[x])) rotate(fa[x]); else rotate(x);
rotate(x);
}
}
int find(int x, int y) {
down(x);
if(a[t[x][0]].siz >= y) return find(t[x][0], y);
if(a[t[x][0]].siz + 1 == y) return x;
return find(t[x][1], y - a[t[x][0]].siz - 1);
}
void Init() {
int root;
scanf("%d", &n);
a[1].siz = 1;
fo(i, 1, n) {
scanf("%lld", &a[i + 1].z);
fa[i] = i + 1; t[i + 1][0] = i; update(i + 1);
}
fa[n + 1] = n + 2; t[n + 2][0] = n + 1; update(n + 2);
root = n + 2; td = n + 2;
scanf("%d", &m);
fo(i, 1, m) {
char s[10]; int x, y, z, l, r;
scanf("%s", s); scanf("%d %d", &x, &y);
if(s[0] == 'Q') {
l = find(root, x); r = find(root, y + 2);
splay(l, 0); splay(r, l); root = l;
printf("%lld\n", a[t[r][0]].sqr % mo);
}
if(s[0] == 'I') {
l = find(root, x); r = find(root, x + 1);
splay(l, 0); splay(r, l);
fa[++ td] = r; a[td].siz = 1; a[td].z = y; a[td].sum = y; a[td].sqr = (ll)y * y;
t[r][0] = td;
splay(td, 0); root = td;
}
if(s[0] == 'A') {
scanf("%d", &z);
l = find(root, x); r = find(root, y + 2);
splay(l, 0); splay(r, l);
chan(t[r][0], z);
root = t[r][0];
splay(t[r][0], 0);
}
}
}
int main() {
freopen("4216.in", "r", stdin);
freopen("4216.out", "w", stdout);
Init();
}