还教室 (线段树+暴力)

还教室

【引子】
还记得 NOIP2012 提高组 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” (不含引号)。

【样例输入】
5 4
1 2 3 4 5
1 1 2 3
2 2 4
3 2 4
3 1 5

【样例输出】
4/1
2/3
14/25

【数据规模与约定】
所有测试点的数据规模如下:
测试点编号 n, m 的规模 约定
1 1 ≤ n, m ≤50 不存在操作 3
2 1 ≤ n, m ≤100 不存在操作 3
3 1 ≤ n, m ≤500
4 1 ≤ n, m ≤1,000
5 1 ≤ n, m ≤2,500
6 1 ≤ n, m ≤5,000
7 1 ≤ n, m ≤50,000 不存在操作 3
8 1 ≤ n, m ≤60,000 不存在操作 3
9 1 ≤ n, m ≤80,000 不存在操作 3
10 1 ≤ n, m ≤100,000 不存在操作 3

对于全部测试数据满足:1 ≤ l ≤ r ≤ n,0 ≤ ai ≤ 10,1 ≤ d ≤3,
操作 1 的数量不超过 10%。
ai 和 d 的范围很小及操作 1 数量很少的原因是为了保证答案的分子不会很大, 以防止答案的分子溢出 64 位整数的范围, 这与题目做法无关。

嗯,这是一道分块写的题目,前五个数据点很容易,直接暴力就可以了。 至于后面的四个点,虽然数据很大,但是没有3操作,所以我们可以用线段树解决,用线段树记录区间和,然后每次查询即可。

program mys;
type
ab=record
l,r,w,c:longint;
end;
var n,m,i,j,k,z,x,y,p:longint;
num,ans,o,sum:int64;
a:array[0..1000000]of int64;
f:array[0..1000000]of ab;

procedure built(x,y,k:longint);
var mid:longint;
begin
f[k].l:=x;
f[k].r:=y;
if x=y then
begin
f[k].w:=a[x];
exit;
end;
mid:=(x+y) div 2;
built(x,mid,k*2);
built(mid+1,y,k*2+1);
f[k].w:=f[k*2].w+f[k*2+1].w;
end;

procedure change(x,y,k:longint);
var mid:longint;
begin
if (f[k].l=x)and(f[k].r=y) then
begin
f[k].w:=f[k].w+(f[k].r-f[k].l+1)*p;
f[k].c:=f[k].c+p;
exit;
end;
if f[k].c<>0 then
begin
f[k*2].w:=f[k*2].w+(f[k*2].r-f[k*2].l+1)*f[k].c;
f[k*2].c:=f[k*2].c+f[k].c;
f[k*2+1].w:=f[k*2+1].w+(f[k*2+1].r-f[k*2+1].l+1)*f[k].c;
f[k*2+1].c:=f[k*2+1].c+f[k].c;
f[k].c:=0;
end;
mid:=(f[k].l+f[k].r) div 2;
if y<=mid then change(x,y,k*2)
else if x>mid then change(x,y,k*2+1)
else
begin
change(x,mid,k*2);
change(mid+1,y,k*2+1);
end;
f[k].w:=f[k*2].w+f[k*2+1].w;
end;

function add(x,y,k:longint):int64;
var mid:longint;
begin
if (f[k].l=x)and(f[k].r=y) then
exit(f[k].w);
if f[k].c<>0 then
begin
f[k*2].w:=f[k*2].w+(f[k*2].r-f[k*2].l+1)*f[k].c;
f[k*2].c:=f[k*2].c+f[k].c;
f[k*2+1].w:=f[k*2+1].w+(f[k*2+1].r-f[k*2+1].l+1)*f[k].c;
f[k*2+1].c:=f[k*2+1].c+f[k].c;
f[k].c:=0;
end;
mid:=(f[k].l+f[k].r) div 2;
if y<=mid then exit(add(x,y,k*2))
else if x>mid then exit(add(x,y,k*2+1))
else
exit(add(x,mid,k*2)+add(mid+1,y,k*2+1));
end;

function gcd(a,b:int64):int64;
begin
if a mod b=0 then exit(b)
else exit(gcd(b,a mod b));
end;

begin
assign(input,'classroom.in');reset(input);
assign(output,'classroom.out');rewrite(output);
readln(n,m);
if (n<=5000)and(m<=5000) then
begin
for i:=1 to n do
read(a[i]);
readln;
for k:=1 to m do
begin
read(z);
if z=1 then
begin
readln(x,y,p);
for i:=x to y do
a[i]:=a[i]+p;
end;
if z=2 then
begin
readln(x,y);
ans:=0;
for i:=x to y do
ans:=ans+a[i];
if ans=0 then
begin
writeln('0/1');
continue;
end;
num:=y-x+1;
o:=gcd(ans,num);
ans:=ans div o;
num:=num div o;
writeln(ans,'/',num);
end;
if z=3 then
begin
readln(x,y);
ans:=0;
sum:=0;
for i:=x to y do
ans:=ans+a[i];
if ans=0 then
begin
writeln('0/1');
continue;
end;
num:=y-x+1;
for i:=x to y do
sum:=sum+(a[i]*num-ans)*(a[i]*num-ans);
if sum=0 then
begin
writeln('0/1');
continue;
end;
num:=num*num*num;
o:=gcd(sum,num);
sum:=sum div o;
num:=num div o;
writeln(sum,'/',num);
end;
end;
close(input);
close(output);
halt; 

end;
for i:=1 to n do
read(a[i]);
built(1,n,1); 
for i:=1 to m do
begin
read(z);
if z=1 then
begin
readln(x,y,p);
change(x,y,1);
end;
if z=2 then
begin
readln(x,y);
ans:=add(x,y,1);
if ans=0 then
begin
writeln('0/1');
continue;
end;
num:=y-x+1;
o:=gcd(ans,num);  
ans:=ans div o;
num:=num div o;
writeln(ans,'/',num);
end;
end;
close(input);
close(output);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值