题目描述:
qn姐姐最好了~
qn姐姐给你了一个长度为n的序列还有m次操作让你玩,
1 l r 询问区间[l,r]内的元素和
2 l r 询问区间[l,r]内的元素的平方 和
3 l r x 将区间[l,r]内的每一个元素都乘上x
4 l r x 将区间[l,r]内的每一个元素都加上x
输入描述:
第一行两个数n,m
接下来一行n个数表示初始序列
就下来m行每行第一个数为操作方法opt,
若opt=1或者opt=2,则之后跟着两个数为l,r
若opt=3或者opt=4,则之后跟着三个数为l,r,x
操作意思为题目描述里说的
输出描述:
对于每一个操作1,2,输出一行表示答案
示例1
输入
5 6
1 2 3 4 5
1 1 5
2 1 5
3 1 2 1
4 1 3 2
1 1 4
2 2 3
输出
15
55
16
41
备注:
对于100%的数据 n=10000,m=200000 (注意是等于号)
保证所有询问的答案在long long 范围内
出题人题解:
显然,线段树
记录4个东西,区间和tree[root][0],区间平方和 tree[root][1],乘法懒标记 add2[root],加法懒标记add1[root] 。
查询的话就是常规查询,打标记就是线段树2板子一样,
初值:add1[root]=0,add2[root]=1;
加法:add1[root]+=dx
乘法:add2[root]*=dx;
然后考虑更新答案
当前区间[l,r] ,当前节点root,这里面每个元素都变成了( a[i]为更新后, x[i]为更新前)
所以
利用线段树处理区间和与区间平方和
利用性质(a+b)^2=a^2+2ab+b^2 ,(ab)^2=a^2b^2 可判断出区间平方和的变动情况,然后进行修改。
区间和的话比较容易了,
然后lazy有点麻烦
然后就标准线段树板子
线段树模板:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 10005
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
long long n,m,tree[maxn<<2][2],add1[maxn<<2],add2[maxn<<2];
void pushup(long long root)
{
tree[root][0]=tree[root<<1][0]+tree[root<<1|1][0];
tree[root][1]=tree[root<<1][1]+tree[root<<1|1][1];
}
void pushdown1(long long l,long long r,long long root)
{ //加法下推
if(add1[root])
{
add1[root<<1]+=add1[root]; //+号不能少,切记
add1[root<<1|1]+=add1[root];
long long x=tree[root<<1][0];
long long y=tree[root<<1|1][0];
tree[root<<1][0]+=l*add1[root];
tree[root<<1|1][0]+=r*add1[root];
tree[root<<1][1]+=2*x*add1[root]+l*add1[root]*add1[root];
tree[root<<1|1][1]+=2*y*add1[root]+r*add1[root]*add1[root];
add1[root]=0;
}
}
void pushdown2(long long l,long long r,long long root)
{ //乘法下推
if(add2[root]!=1)
{
add2[root<<1]*=add2[root]; //*号不能少,切记
add2[root<<1|1]*=add2[root];
tree[root<<1][0]*=add2[root];
tree[root<<1|1][0]*=add2[root];
tree[root<<1][1]*=add2[root]*add2[root];
tree[root<<1|1][1]*=add2[root]*add2[root];
add2[root]=1;
}
}
void build(long long l,long long r,long long root)
{
add1[root]=0;
add2[root]=1;
if(l==r)
{
scanf("%lld",&tree[root][0]);
tree[root][1]=tree[root][0]*tree[root][0];
return;
}
long long mid=(l+r)>>1;
build(lson);
build(rson);
pushup(root);
}
void update1(long long L,long long R,long long C,long long l,long long r,long long root)
{ //加法更新
if(L<=l&&r<=R)
{
long long x=tree[root][0];
tree[root][0] += (r-l+1)*C;
tree[root][1] += 2*x*C+(r-l+1)*C*C;
add1[root] += C;
return ;
}
long long mid = (l+r)/2;
pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
if(L<=mid)
update1(L,R,C,lson);
if(R>mid)
update1(L,R,C,rson);
pushup(root);
}
void update2(long long L,long long R,long long C,long long l,long long r,long long root)
{ //乘法更新
if(L<=l&&r<=R)
{
tree[root][0] *= C;
tree[root][1] *= C*C;
add2[root] *= C; if(add1[root]) add1[root] *= C;
return ;
}
long long mid = (l+r)/2;
pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
if(L<=mid)
update2(L,R,C,lson);
if(R>mid)
update2(L,R,C,rson);
pushup(root);
}
long long query(long long L,long long R,long long c,long long l,long long r,long long root)
{
if(L<=l&&R>=r)
{
if(c==1)
return tree[root][0];
if(c==2)
return tree[root][1];
}
long long ans=0,mid=(l+r)>>1;
pushdown2(mid-l+1,r-mid,root); pushdown1(mid-l+1,r-mid,root);
if(L<=mid)
ans+=query(L,R,c,lson);
if(R>mid)
ans+=query(L,R,c,rson);
return ans;
}
int main()
{
cin>>n>>m;
build(1,n,1);
while(m--)
{
long long op,x,y,val;
scanf("%lld",&op);
if(op==1||op==2)
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",query(x,y,op,1,n,1));
}
else if(op==3||op==4)
{
scanf("%lld%lld%lld",&x,&y,&val);
if(op==3)
update2(x,y,val,1,n,1);
else
update1(x,y,val,1,n,1);
}
}
return 0;
}
转自:题解
第二种。。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define N 100005
using namespace std;
typedef long long LL;
struct Node
{
LL lazy, mulzy, sum, mul;
}tree[N];
LL a[10005];
int n, m;
void Build(int G, int l, int r)
{
if (l == r)
{
tree[G].mulzy = 1,
tree[G].sum = a[l],
tree[G].mul = a[l] * a[l];
return;
}
int mid = (l + r) >> 1;
Build(G * 2, l, mid);
Build(G * 2 + 1, mid + 1, r);
tree[G].mulzy = 1;
tree[G].sum = tree[G * 2].sum + tree[G * 2 + 1].sum;
tree[G].mul = tree[G * 2].mul + tree[G * 2 + 1].mul;
}
void Updata(int p, int l, int r)
{
if (tree[p].lazy == 0 && tree[p].mulzy == 1)
return;
int mid = (l + r) >> 1;
tree[p * 2].mul = tree[p * 2].mul * tree[p].mulzy * tree[p].mulzy + 2 * (tree[p].mulzy * tree[p].lazy) * tree[p * 2].sum + (mid - l + 1) * tree[p].lazy * tree[p].lazy;
tree[p * 2 + 1].mul = tree[p * 2 + 1].mul * tree[p].mulzy * tree[p].mulzy + 2 * (tree[p].mulzy * tree[p].lazy) * tree[p * 2 + 1].sum + (r - mid) * tree[p].lazy * tree[p].lazy;
tree[p * 2].sum = tree[p * 2].sum * tree[p].mulzy + (mid - l + 1) * tree[p].lazy;
tree[p * 2 + 1].sum = tree[p * 2 + 1].sum * tree[p].mulzy + (r - mid) * tree[p].lazy; tree[p * 2].mulzy = tree[p * 2].mulzy * tree[p].mulzy;
tree[p * 2 + 1].mulzy = tree[p * 2 + 1].mulzy * tree[p].mulzy;
tree[p * 2].lazy = tree[p * 2].lazy * tree[p].mulzy + tree[p].lazy;
tree[p * 2 + 1].lazy = tree[p * 2 + 1].lazy * tree[p].mulzy + tree[p].lazy;
tree[p].lazy = 0, tree[p].mulzy = 1;
}
void Insert(int p, int l, int r, int a, int b, LL x, int opt)
{
int mid = (l + r) >> 1;
if (l == a && r == b)
{
if (opt == 3)
tree[p].mul = tree[p].mul * x * x,
tree[p].sum = tree[p].sum * x,
tree[p].lazy *= x, tree[p].mulzy *= x;
else
tree[p].mul += 2 * x * tree[p].sum + (r - l + 1) * x * x, tree[p].sum = tree[p].sum + (r - l + 1) * x, tree[p].lazy += x;
return;
}
Updata(p,l,r);
if (mid >= b)
Insert(p * 2, l, mid, a, b, x, opt);
else if (a > mid)
Insert(p * 2 + 1, mid + 1, r, a, b, x, opt);
else
{
Insert(p * 2, l, mid, a, mid, x, opt);
Insert(p * 2 + 1, mid + 1, r, mid + 1, b, x, opt);
}
tree[p].sum = tree[p * 2].sum + tree[p * 2 + 1].sum;
tree[p].mul = tree[p * 2].mul + tree[p * 2 + 1].mul;
}
LL Get_sum(int p, int l, int r, int a, int b, int opt)
{
int mid = (l + r) >> 1;
if (l == a && r == b)
{
if (opt == 1)
return tree[p].sum;
else return tree[p].mul;
}
Updata(p, l, r);
if (mid >= b)
return Get_sum(p * 2, l, mid, a, b, opt);
else if (a > mid)
return Get_sum(p * 2 + 1, mid + 1, r, a, b, opt);
else return Get_sum(p * 2, l, mid, a, mid, opt) + Get_sum(p * 2 + 1, mid + 1, r, mid + 1, b, opt);
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
Build(1, 1, n);
for (int i = 1; i <= m; i++)
{
int opt, l, r;
LL x;
scanf("%d", &opt);
if (opt == 1 || opt == 2)
{
scanf("%d %d", &l, &r);
printf("%lld\n", Get_sum(1, 1, n, l, r, opt));
}
if (opt == 3 || opt == 4)
{
scanf("%d %d %lld", &l, &r, &x);
Insert(1, 1, n, l, r, x, opt);
}
}
return 0;
}