J--外挂(线段树维护平方的区间和)

链接:https://ac.nowcoder.com/acm/contest/917/J
来源:牛客网
 

 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 65536K,其他语言131072K
64bit IO Format: %lld

题目描述

我的就是我的,你也是我的,记住了,狐狸!

                                                                      ——韩信-白龙吟

 

对于打赌输了的小T会遭受到制裁,小s修改了数据库使他可以派出许多军队来围攻小T.

 

很不幸,小T与小s打赌打输了,现在小T遭受着枪林弹雨与十面埋伏,因为小T是神所以他决定要扭转局势。

 

他要修改数据库!

 

数据总库的信号墙有n个电极插头,每个插头有一个信号aiai,

 

小T可以使在区间[ l,r ][ l,r ]内的所有信号加上一个值k。

 

对于区间[ l,r ][ l,r ]的信号强度有一个计算公式:

 

我们定义

f(k)=ak×∑rj=k+1ajf(k)=ak×∑j=k+1raj

 

则信号强度就为:

∑ri=lf(i)∑i=lrf(i)

 

你可以认为f(i)就是第i个插头的信号强度。

 

现在小T一会儿修改信号值,一会儿询问信号强度,你是数据库的管理员,为了不被小TD,所以你要告诉他信号强度是多少。

 

 

注:本系列题不按难度排序哦

输入描述:

第一行两个整数n,Q

第二行n个整数代表a

后Q行代表操作:

一操作:1 l r x1 l r x代表区间[ l,r ][ l,r ]加x。

二操作:2 l r2 l r代表区间询问。

输出描述:

每一行一个数字,表示对于一个二操作的答案。

示例1

输入

复制

5 2
1 2 3 4 5
1 1 2 1
2 1 2

输出

复制

6

说明

 

样例解释:1 1 2 1使a[1]~a[2]的值每个都加了1, 即a[1]=2, a[2]=3,所以2 1 2=a[1]*a[2]=2*3=6

 

保证所有二操作的答案都是在long longlong long范围内(如果你不相信,可以写高精)。


时空限制为标程的5倍,放心卡常。

备注:

 

100%  1≤n,Q≤105100%  1≤n,Q≤105

对于所有ai≤100ai≤100

不会写看题解:

透过这道题 我学会了如何用线段数维护每一位的数的平方  的区间和。 也知道了如果是区间内任意两个数相乘之和的答案是这样求得。很不错得一道题,学到了学到了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll c1[N*4],c2[N*4],a[N],lazy[N*4];
int n,m;
void build(int id,int l,int r)
{
	if(l==r)
	{
		ll x;
		scanf("%lld",&x);
		c1[id]=x;
		c2[id]=x*x;
		return ;
	}
	int mid=l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	c1[id]=c1[id<<1]+c1[id<<1|1];
	c2[id]=c2[id<<1]+c2[id<<1|1];
}
void pushdown(int id,int l,int r)
{
	if(lazy[id])
	{
		int mid=l+r>>1;
		int l1=mid-l+1;
		int l2=r-mid;
		c2[id<<1]+=l1*lazy[id]*lazy[id]+2*c1[id<<1]*lazy[id];
		c2[id<<1|1]+=l2*lazy[id]*lazy[id]+2*c1[id<<1|1]*lazy[id];
		
		c1[id<<1]+=l1*lazy[id];
		c1[id<<1|1]+=l2*lazy[id];
		
		lazy[id<<1]+=lazy[id];
		lazy[id<<1|1]+=lazy[id];
		lazy[id]=0;
	}
}
void up(int id,int l,int r,int ql,int qr,ll val)
{
	if(ql<=l&&r<=qr)
	{
		int len=r-l+1;
		c2[id]+=val*val*len+2*c1[id]*val;
		c1[id]+=val*len;
		lazy[id]+=val;
		return ;
	}
	pushdown(id,l,r);
	int mid=l+r>>1;
	if(ql<=mid) up(id<<1,l,mid,ql,qr,val);
	if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,val);
	c1[id]=c1[id<<1]+c1[id<<1|1];
	c2[id]=c2[id<<1]+c2[id<<1|1];
}

ll qu(int id,int l,int r,int ql,int qr,int op)
{
	if(ql<=l&&r<=qr) 
	{
		if(op==1)	return c1[id];
		else return c2[id];
	}
	pushdown(id,l,r);
	ll ans=0;
	int mid=l+r>>1;
	if(ql<=mid) ans+=qu(id<<1,l,mid,ql,qr,op);
	if(qr>mid) ans+=qu(id<<1|1,mid+1,r,ql,qr,op);
	return ans;
}

int main()
{
	cin>>n>>m;
	build(1,1,n);
	for(int i=1;i<=m;++i)
	{
		int ty,l,r;
		ll val;
		scanf("%d%d%d",&ty,&l,&r);
		if(ty==1) 
		{
			scanf("%lld",&val);
			up(1,1,n,l,r,val);
		}
		else
		{
			ll nu1=qu(1,1,n,l,r,1);
			ll nu2=qu(1,1,n,l,r,2);
			printf("%lld\n",(nu1*nu1-nu2)/2);
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙大学ccsu_deer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值