Description
在接受借教室请求的n 天中,第i 天剩余的教室为ai个。作为大学借教室服务的负责人,你需要完成如下三种操作共m次:
① 第 l 天到第r 天,每天被归还d 个教室。
② 询问第l 天到第r 天教室个数的平均数。
③ 询问第l 天到第r 天教室个数的方差。
Input
第一行包括两个正整数n 和m,其中n 为借教室的天数,m为操作次数。
接下来一行,共包含n个整数,第i 个整数表示第i天剩余教室数目为ai个。
接下来m 行,每行的第一个整数为操作编号(只能为1 或2 或3),接下来包含两个正整数l 和r,若操作编号为1,则接下来再包含一个正整数d。
Output
对于每个操作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
HINT
1 ≤ n, m ≤ 100,000 ,1 ≤ l ≤ r ≤ n,0 ≤ ai ≤ 10,1 ≤ d ≤ 3,操作1 的数量不超过10%。
Key To Problem
这是一道线段树的题
首先方差绝对不可以直接来求,而是要用一个推导的公式
s2=(Σni=1x2in)−((Σni=1xi)2n2)
我们需要两个线段树,数组f记录区间和,数组sum记录区间平方和
修改前
sumrt=f2l+f2l+1+......+f2r
frt=fl+fl+1+......+fr
修改后
sumrt=(fl+d)2+(fl+1+d)2+......+(fr+d)2
sumrt=(f2l+f2l+1+......+f2r)+2∗d∗(fl+fl+1+......+fr)+d2∗(r−l+1)
sumrt=sumrt+2∗d∗frt+d2∗(r−l+1)
剩下的就是普通的区间修改加上求和之类的啦
CODE
#include<cstdio>
#include<algorithm>
#define N 100010
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
typedef long long ll;
int n,m;
ll f[N<<2];
ll sum[N<<2];
ll add[N<<2];
ll gcd(ll x,ll y)
{
if(y==0)
return x;
ll t=gcd(y,x%y);
return t;
}
void PushUp(int rt)
{
f[rt]=f[ls]+f[rs];
sum[rt]=sum[ls]+sum[rs];
}
void PushDown(int rt,ll k)
{
if(add[rt])
{
add[ls]+=add[rt];
add[rs]+=add[rt];
sum[ls]+=2*add[rt]*f[ls]+(k-(k>>1))*add[rt]*add[rt];
sum[rs]+=2*add[rt]*f[rs]+(k>>1)*add[rt]*add[rt];
f[ls]+=add[rt]*(k-(k>>1));
f[rs]+=add[rt]*(k>>1);
add[rt]=0;
}
}
void build(int l,int r,int rt)
{
add[rt]=0;
if(l==r)
{
scanf("%d",&f[rt]);
sum[rt]=f[rt]*f[rt];
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int L,int R,ll s,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
add[rt]+=s;
sum[rt]+=2*s*f[rt]+(r-l+1)*s*s;
f[rt]+=s*(ll)(r-l+1);
return ;
}
PushDown(rt,(ll)r-l+1);
int mid=(l+r)>>1;
if(mid>=L)
update(L,R,s,lson);
if(mid<R)
update(L,R,s,rson);
PushUp(rt);
}
ll query1(int L,int R,int l,int r,int rt)
{
if(l>=L&&r<=R)
return f[rt];
PushDown(rt,r-l+1);
int mid=(l+r)>>1;
ll ret=0;
if(mid>=L)
ret+=query1(L,R,lson);
if(mid<R)
ret+=query1(L,R,rson);
return ret;
}
ll query2(int L,int R,int l,int r,int rt)
{
if(l>=L&&r<=R)
return sum[rt];
PushDown(rt,r-l+1);
int mid=(l+r)>>1;
ll ret=0;
if(mid>=L)
ret+=query2(L,R,lson);
if(mid<R)
ret+=query2(L,R,rson);
return ret;
}
int main()
{
freopen("classroom.in","r",stdin);
freopen("classroom.out","w",stdout);
scanf("%d%d",&n,&m);
build(1,n,1);
for(int i=1;i<=m;i++)
{
int a,x,y;
ll z;
scanf("%d%d%d",&a,&x,&y);
if(a==1)
{
scanf("%I64d",&z);
update(x,y,z,1,n,1);
}else
{
if(a==2)
{
ll ans=query1(x,y,1,n,1);
ll s=y-x+1;
ll k=gcd(ans,s);
printf("%I64d/%I64d\n",ans/k,s/k);
}else
{
ll s=y-x+1;
ll p=query1(x,y,1,n,1);
p*=p;
ll ans=query2(x,y,1,n,1)*s-p;
s*=s;
ll k=gcd(ans,s);
printf("%I64d/%I64d\n",ans/k,s/k);
}
}
}
return 0;
}