还教室

题目描述 Description###

在接受借教室请求的 (n) 天中,第 (i) 天剩余的教室为 (a_i) 个。作为大学借教室服务的负责人,你需要完成如下三种操作共 (m) 次:
① 第 (l) 天到第 (r) 天,每天被归还 (d) 个教室。
② 询问第 (l) 天到第 (r) 天教室个数的平均数。
③ 询问第 (l) 天到第 (r) 天教室个数的方差。

输入描述 Input Description###

第一行包括两个正整数 (n)(m) ,其中 (n) 为借教室的天数,(m) 为操作次数。
接下来一行, 共包含 (n) 个整数, 第 (i) 个整数表示第 (i) 天剩余教室数目为 (a_i) 个。
接下来 (m) 行,每行的第一个整数为操作编号(只能为 (1)(2)(3)) ,接下来
包含两个正整数 (l)(r),若操作编号为 (1),则接下来再包含一个正整数 (d)

输出描述 Output Description###

对于每个操作 (2) 和操作 (3) ,输出一个既约分数(分子与分母互质)表示询问的答案(详见样例) 。若答案为 (0) ,请输出“0/1” (不含引号) 。

样例输入 Sample Input###

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

样例输出 Sample Output###

4/1
2/3
14/25

数据范围及提示 Data Size & Hint###

(1<=n,m<=100000)

之前的一些废话###

听说已经出期中考试成绩了,不管了不管了!

题解###

练习线段树的,维护一下区间和与区间平方和即可。

代码###

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
typedef long long LL;
#define mem(a,b) memset(a,b,sizeof(a))
typedef pair<LL,LL> PII;
#define X first
#define Y second
#define mp make_pair
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=100010;
int n,m,tp,x,y,z,a[maxn];
LL sum[maxn<<2],qsum[maxn<<2],tag[maxn<<2];
void pushup(int l,int r,int o)
{
	if(l==r)return;
	int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
	sum[o]=sum[lo]+sum[ro];
	qsum[o]=qsum[lo]+qsum[ro];
	return;
}
void pushdown(int l,int r,int o)
{
	if(l==r)return;
	int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
	tag[lo]+=tag[o];tag[ro]+=tag[o];
	qsum[lo]+=(2ll*tag[o]*sum[lo]+(LL)(mid-l+1)*tag[o]*tag[o]);
	qsum[ro]+=(2ll*tag[o]*sum[ro]+(LL)(r-mid)*tag[o]*tag[o]);
	sum[lo]+=tag[o]*(LL)(mid-l+1);sum[ro]+=tag[o]*(LL)(r-mid);
	tag[o]=0;
}
void build(int l,int r,int o)
{
	if(l==r)
	{
		sum[o]=a[l];
		qsum[o]=(LL)a[l]*(LL)a[l];
		return;
	}
	int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
	build(l,mid,lo);build(mid+1,r,ro);
	pushup(l,r,o);
}
void change(int l,int r,int o,int ql,int qr,LL x)
{
	if(l==ql && r==qr)
	{
		tag[o]+=x;
		qsum[o]+=(2ll*x*sum[o]+(LL)(r-l+1)*x*x);
		sum[o]+=(LL)(r-l+1)*x;
		return;
	}
	pushdown(l,r,o);
	int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
	if(qr<=mid)change(l,mid,lo,ql,qr,x);
	else if(ql>mid)change(mid+1,r,ro,ql,qr,x);
	else change(l,mid,lo,ql,mid,x),change(mid+1,r,ro,mid+1,qr,x);
	pushup(l,r,o);
}
LL query1(int l,int r,int o,int ql,int qr)
{
	if(l==ql && r==qr)return sum[o];
	pushdown(l,r,o);
	int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
	if(qr<=mid)return query1(l,mid,lo,ql,qr);
	else if(ql>mid)return query1(mid+1,r,ro,ql,qr);
	else return query1(l,mid,lo,ql,mid)+query1(mid+1,r,ro,mid+1,qr);
}
LL query2(int l,int r,int o,int ql,int qr)
{
	if(l==ql && r==qr)return qsum[o];
	pushdown(l,r,o);
	int mid=(l+r)>>1,lo=o<<1,ro=lo|1;
	if(qr<=mid)return query2(l,mid,lo,ql,qr);
	else if(ql>mid)return query2(mid+1,r,ro,ql,qr);
	else return query2(l,mid,lo,ql,mid)+query2(mid+1,r,ro,mid+1,qr);
}
LL gcd(LL a,LL b){return b==0ll ? a : gcd(b,a%b);}
PII yuefen(PII a)
{
	LL c=gcd(a.X,a.Y);
	return mp(a.X/c,a.Y/c);
}
void print(PII a){a=yuefen(a);printf("%lld/%lld
",a.X,a.Y);}
int main()
{
	freopen("rand.in","r",stdin);
	//freopen("myans.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	build(1,n,1);
	while(m--)
	{
		tp=read();x=read();y=read();
		if(tp==1)z=read(),change(1,n,1,x,y,(LL)z);
		else if(tp==2)print(mp(query1(1,n,1,x,y),(LL)(y-x+1)));
		else if(tp==3)
		{
			LL sum1=query1(1,n,1,x,y),sum2=query2(1,n,1,x,y),len=y-x+1ll;
			print(mp((len)*sum2-sum1*sum1,len*len));
		}
	}
	return 0;
}

总结###

相关线段树易错点已整理到我的笔记本中。

原文地址:https://www.cnblogs.com/FYH-SSGSS/p/7809886.html