[HAOI2012]高速公路

Posted by Dispwnl on December 3, 2018

题目

题目描述

Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。

Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。

政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。

无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l<r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?

输入输出格式

输入格式:

第一行2个正整数N,M,表示有N个收费站,M次调整或询问

接下来M行,每行将出现以下两种形式中的一种

C l r v 表示将第l个收费站到第r个收费站之间的所有道路的通行费全部增加v

Q l r 表示对于给定的l,r,要求回答小A的问题

所有C与Q操作中保证1<=l<r<=N

输出格式:

对于每次询问操作回答一行,输出一个既约分数

若答案为整数a,输出a/1

输入输出样例

输入样例#1:

4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4

输出样例#1:

1/1
8/3
17/6

说明

所有C操作中的v的绝对值不超过10000

在任何时刻任意道路的费用均为不超过10000的非负整数

所有测试点的详细情况如下表所示

Test NN MM
11 1010 1010
22 100100 100100
33 10001000 10001000
44 1000010000 1000010000
55 5000050000 5000050000
66 6000060000 6000060000
77 7000070000 7000070000
88 8000080000 8000080000
99 9000090000 9000090000
1010 100000100000 100000100000

题解

假设期望值为EE,则E=i=lrvali(il+1)(ri+1)(rl+1)(rl+2)2E=\frac{\sum_{i=l}^{r}val_i(i-l+1)(r-i+1)}{\frac{(r-l+1)(r-l+2)}{2}}

下面的那部分显然是个常数,所以只用看上面部分

i=lrvali(il+1)(ri+1)\sum_{i=l}^{r}val_i(i-l+1)(r-i+1)

拆开括号得:i=lrvali(i×ri2+il×r+i×ll+ri+1)\sum_{i=l}^{r}val_i(i\times r-i^2+i-l\times r+i\times l-l+r-i+1)

合并得:i=lrvali(i(l+r)i2+(rll×r+1))\sum_{i=l}^{r}val_i(i(l+r)-i^2+(r-l-l\times r+1))

拆开得:(l+r)i=lrvali×ii=lrvali×i2+(rll×r+1)i=lrvali(l+r)\sum_{i=l}^{r}val_i\times i-\sum_{i=l}^{r}val_i\times i^2+(r-l-l\times r+1)\sum_{i=l}^{r}val_i

显然这个东西可以用线段树维护,维护vali,vali×i,vali×i2val_i,val_i\times i,val_i\times i^2的区间和即可

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
# define tl (k<<1)
# define tr (k<<1|1)
# define mid (l+r>>1)
# define LL long long
using namespace std;
const int MAX=1e5+5;
struct p{
	LL x,_x,__x,tag;
}s[MAX<<2];
int n,m;
LL sum[MAX],_sum[MAX];
char a[5];
int read()
{
	int x=0,fl=1;
	char ch=getchar();
	for(;!isdigit(ch);fl=(ch=='-')?-1:1,ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x*fl;
}
p pus(p b,p c,LL Tag=0)
{
	p a;
	a.tag=Tag,a.x=b.x+c.x,a._x=b._x+c._x,a.__x=b.__x+c.__x;
	return a;
}
void down(int l,int r,int k)
{
	if(!s[k].tag) return;
	LL f=s[k].tag;
	s[k].tag=0,s[tl].tag+=f,s[tr].tag+=f,s[tl].x+=(mid-l+1)*f,s[tr].x+=(r-mid)*f,s[tl]._x+=(sum[mid]-sum[l-1])*f,s[tr]._x+=(sum[r]-sum[mid])*f,s[tl].__x+=(_sum[mid]-_sum[l-1])*f,s[tr].__x+=(_sum[r]-_sum[mid])*f;
}
void change(int l,int r,int k,int L,int R,int dis)
{
	if(l==L&&r==R)
	{
		s[k].x+=1ll*(r-l+1)*dis,s[k]._x+=1ll*(sum[r]-sum[l-1])*dis,s[k].__x+=1ll*(_sum[r]-_sum[l-1])*dis;
		return void(s[k].tag+=dis);
	}
	down(l,r,k);
	if(R<=mid) change(l,mid,tl,L,R,dis);
	else if(L>mid) change(mid+1,r,tr,L,R,dis);
	else change(l,mid,tl,L,mid,dis),change(mid+1,r,tr,mid+1,R,dis);
	s[k]=pus(s[tl],s[tr],s[k].tag);
}
p ask(int l,int r,int k,int L,int R)
{
	if(l==L&&r==R) return s[k];
	down(l,r,k);
	if(R<=mid) return ask(l,mid,tl,L,R);
	if(L>mid) return ask(mid+1,r,tr,L,R);
	return pus(ask(l,mid,tl,L,mid),ask(mid+1,r,tr,mid+1,R));
}
void ASK(int l,int r)
{
	p A=ask(1,n,1,l,r);
	LL L=1ll*(r-l+1)*(r-l+2)>>1,A1=A.x*(r-l-1ll*l*r+1)+(l+r)*A._x-A.__x,Gcd=__gcd(A1,L);
	printf("%lld/%lld\n",A1/Gcd,L/Gcd);
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;++i)
	  sum[i]=sum[i-1]+i,_sum[i]=_sum[i-1]+1ll*i*i;
	for(int i=1,l,r;i<=m;++i)
	  {
	  	scanf("%s",a),l=read(),r=read();
	  	if(a[0]=='C') change(1,n,1,l,r-1,read());
	  	else if(a[0]=='Q') ASK(l,r-1);
	  }
	return 0;
}