[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 $N$ $M$
$1$ $10$ $10$
$2$ $100$ $100$
$3$ $1000$ $1000$
$4$ $10000$ $10000$
$5$ $50000$ $50000$
$6$ $60000$ $60000$
$7$ $70000$ $70000$
$8$ $80000$ $80000$
$9$ $90000$ $90000$
$10$ $100000$ $100000$

题解

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

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

$\sum_{i=l}^{r}val_i(i-l+1)(r-i+1)$

拆开括号得:$\sum_{i=l}^{r}val_i(i\times r-i^2+i-l\times r+i\times l-l+r-i+1)$

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

拆开得:$(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$

显然这个东西可以用线段树维护,维护$val_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;
}