题目背景
还记得 NOIP 2012 提高组 Day2 中的借教室吗?时光飞逝,光阴荏苒,两年
过去了,曾经借教室的同学们纷纷归还自己当初租借的教室。请你来解决类似于
借教室的另一个问题。
题目描述
在接受借教室请求的 n 天中,第 i 天剩余的教室为 ai个。作为大学借教室服
务的负责人,你需要完成如下三种操作共 m 次:
① 第 l 天到第 r 天,每天被归还 d 个教室。
② 询问第 l 天到第 r 天教室个数的平均数。
③ 询问第 l 天到第 r 天教室个数的方差。
输入输出格式
输入格式:第一行包括两个正整数 n 和 m,其中 n 为借教室的天数,m 为操作次数。
接下来一行,共包含 n 个整数,第 i 个整数表示第 i 天剩余教室数目为 ai个。
接下来 m 行,每行的第一个整数为操作编号(只能为 1 或 2 或 3),接下来
包含两个正整数 l 和 r,若操作编号为 1,则接下来再包含一个正整数 d。
输出格式:对于每个操作 2 和操作 3,输出一个既约分数(分子与分母互质)表示询问
的答案(详见样例)。若答案为 0,请输出“0/1”(不含引号)。
输入输出样例
输入样例#1:
5 4 1 2 3 4 5 1 1 2 3 2 2 4 3 2 4 3 1 5
输出样例#1:
4/1 2/3 14/25
说明
对于全部测试数据满足:1 ≤ l ≤ r ≤ n,0 ≤ ai ≤ 10,1 ≤ d ≤ 3,操作 1 的数量
不超过 10%。注意:ai和 d 的范围很小及操作 1 数量很少的原因是为了保证答案
的分子不会很大,以防止答案的分子溢出 64 位整数的范围,这与题目做法无关。
线段树裸题。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define MEXP(x) a[x].mexp
#define SIGN(x) a[x].c
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 100010
using namespace std;
int n,m;
struct node{
long long data,c;
unsigned long long mexp;
int l,r;
}a[MAXN<<2];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
long long gcd(long long x,long long y){
if(y==0)return x;
return gcd(y,x%y);
}
inline void pushup(int rt){
DATA(rt)=DATA(LSON)+DATA(RSON);
MEXP(rt)=MEXP(LSON)+MEXP(RSON);
}
inline void pushdown(int rt){
if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;
SIGN(LSON)+=SIGN(rt);
MEXP(LSON)+=SIGN(rt)*SIGN(rt)*WIDTH(LSON)+2*SIGN(rt)*DATA(LSON);
DATA(LSON)+=SIGN(rt)*WIDTH(LSON);
SIGN(RSON)+=SIGN(rt);
MEXP(RSON)+=SIGN(rt)*SIGN(rt)*WIDTH(RSON)+2*SIGN(rt)*DATA(RSON);
DATA(RSON)+=SIGN(rt)*WIDTH(RSON);
SIGN(rt)=0;
}
void buildtree(int l,int r,int rt){
int mid;
LSIDE(rt)=l;
RSIDE(rt)=r;
SIGN(rt)=0;
if(l==r){
DATA(rt)=read();
MEXP(rt)=DATA(rt)*DATA(rt);
return;
}
mid=l+r>>1;
buildtree(l,mid,LSON);
buildtree(mid+1,r,RSON);
pushup(rt);
}
void update(int l,int r,long long c,int rt){
int mid;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
SIGN(rt)+=c;
MEXP(rt)+=c*c*WIDTH(rt)+2*c*DATA(rt);
DATA(rt)+=c*WIDTH(rt);
return;
}
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update(l,r,c,LSON);
if(mid<r)update(l,r,c,RSON);
pushup(rt);
}
long long query_sum(int l,int r,int rt){
int mid;
long long ans=0;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
return DATA(rt);
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans+=query_sum(l,r,LSON);
if(mid<r)ans+=query_sum(l,r,RSON);
return ans;
}
unsigned long long query_mexp(int l,int r,int rt){
int mid;
unsigned long long ans=0;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)
return MEXP(rt);
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans+=query_mexp(l,r,LSON);
if(mid<r)ans+=query_mexp(l,r,RSON);
return ans;
}
inline void single(long long &s1,long long &s2){
long long k=gcd(s1,s2);
s1/=k;s2/=k;
}
int main(){
int f,x,y,k;
n=read();m=read();
buildtree(1,n,1);
while(m--){
f=read();x=read();y=read();
switch(f){
case 1:{
k=read();
update(x,y,k,1);
break;
}
case 2:{
long long s1=query_sum(x,y,1),s2=y-x+1;
if(s1==0)s2=1;
else single(s1,s2);
printf("%lld/%lld\n",s1,s2);
break;
}
case 3:{
long long s1=query_sum(x,y,1),s2=query_mexp(x,y,1),s3=y-x+1,k;
s2=s2*s3-s1*s1;s3*=s3;
if(s2==0)s3=1;
else single(s2,s3);
printf("%lld/%lld\n",s2,s3);
break;
}
}
}
return 0;
}