BZOJ2752: [HAOI2012]高速公路(road)
2752: [HAOI2012]高速公路(road)
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 1734 Solved: 684
[Submit][Status][Discuss]
Description
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将期望花费多少费用呢?
Input
第一行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
Output
对于每次询问操作回答一行,输出一个既约分数
若答案为整数a,输出a/1
Sample Input
4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4
Sample Output
1/1
8/3
17/6
HINT
数据规模
所有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
Source
题解
先把边权弄到点上,所有区间\([l,r]\)变为\([l,r-1]\)
分母是C(r - l + 2, 2)
考虑\(i\in[l,r]\)的点\(i\)对期望的贡献
分子即为
线段树维护\(v_i,\ v_i^2, vi\)的和即可
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
inline long long max(long long a, long long b){return a > b ? a : b;}
inline long long min(long long a, long long b){return a < b ? a : b;}
inline void swap(long long &x, long long &y){long long tmp = x;x = y;y = tmp;}
inline void read(long long &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const long long INF = 0x3f3f3f3f3f3f3f3f;
const long long MAXN = 100000 + 10;
struct Node
{
long long sum_i, sum_i2, sum_v, sum_vi, sum_vi2, len;
long long add;
Node(){sum_i = sum_i2 = sum_v = sum_vi = sum_vi2 = len = add = 0;}
}node[MAXN << 2];
Node merge(Node& a, Node& b)
{
Node re;
re.sum_v = a.sum_v + b.sum_v;
re.sum_vi = a.sum_vi + b.sum_vi;
re.sum_vi2 = a.sum_vi2 + b.sum_vi2;
return re;
}
void pushup(long long o)
{
Node& re = node[o], &a = node[o << 1], &b = node[o << 1 | 1];
re.sum_v = a.sum_v + b.sum_v;
re.sum_vi = a.sum_vi + b.sum_vi;
re.sum_vi2 = a.sum_vi2 + b.sum_vi2;
}
void pushdown(long long o)
{
if(node[o].add)
{
long long v = node[o].add;
for(long long i = 0;i <= 1;++ i)
{
Node &a = node[o << 1 | i];
a.sum_v += a.len * v;
a.sum_vi += a.sum_i * v;
a.sum_vi2 += a.sum_i2 * v;
a.add += v;
}
node[o].add = 0;
}
}
long long n, q;
void build(long long o = 1, long long l = 1, long long r = n)
{
if(l == r)
{
node[o].sum_i = l, node[o].sum_i2 = l * l, node[o].len = 1;
return;
}
long long mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
node[o].len = node[o << 1].len + node[o << 1 | 1].len;
node[o].sum_i = node[o << 1].sum_i + node[o << 1 | 1].sum_i;
node[o].sum_i2 = node[o << 1].sum_i2 + node[o << 1 | 1].sum_i2;
}
void modify(long long ll, long long rr, long long k, long long o = 1, long long l = 1, long long r = n)
{
if(l != r) pushdown(o);
if(ll <= l && rr >= r)
{
node[o].sum_v += k * node[o].len;
node[o].sum_vi += k * node[o].sum_i;
node[o].sum_vi2 += k * node[o].sum_i2;
node[o].add += k;
return;
}
long long mid = (l + r) >> 1;
if(mid >= ll) modify(ll, rr, k, o << 1, l, mid);
if(mid < rr) modify(ll, rr, k, o << 1 | 1, mid + 1, r);
pushup(o);
}
Node ask(long long ll, long long rr, long long o = 1, long long l = 1, long long r = n)
{
if(l != r) pushdown(o);
if(ll <= l && rr >= r) return node[o];
Node a, b, re;
long long mid = (l + r) >> 1;
if(mid >= ll) a = ask(ll, rr, o << 1, l, mid);
if(mid < rr) b = ask(ll, rr, o << 1 | 1, mid + 1, r);
pushup(o);
re = merge(a, b);
return re;
}
char s[10];
long long gcd(long long a, long long b)
{
return !b ? a : gcd(b, a%b);
}
int main()
{
read(n), read(q);
build();
for(long long i = 1;i <= q;++ i)
{
scanf("%s", s + 1);
long long l, r, v;read(l), read(r);-- r;
if(s[1] == 'C') read(v), modify(l, r, v);
else
{
Node a = ask(l, r);
long long zi = (r - l - l * r + 1) * a.sum_v + (l + r) * a.sum_vi - a.sum_vi2, mu = (r - l + 2) * (r - l + 1) / 2;
long long g = gcd(zi, mu);
printf("%lld/%lld\n", zi/g, mu/g);
}
}
return 0;
}