您的位置:首页 > 其它

Bzoj 2752: [HAOI2012]高速公路(road)

2017-06-23 19:19 176 查看
传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=2752

题面:

  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 将期望花费多少费用呢?

数据范围: n,m≤105

题解: 这道题的修改直接线段树即可,关键是询问,询问的是一段区间内的所有连续子区间的和,对于这个我们在每个节点顺便维护当前区间的大小,所有前缀的和,所有后缀的和和所有连续子区间的和,这样合并的时候就可以用用前三者算出当前所有连续子区间的和。

#include<bits/stdc++.h>
typedef long long ll;
const int N = 1e5 + 10;
const int Node = N * 4;
template <typename T> void read(T &x) {
x = 0; T f = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f *= -1;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
struct rec{
int size;
ll sum, suml, sumr, suma;
}tr[Node];
rec operator + (const rec &l, const rec &r) {
return (rec) {l.size + r.size, l.sum + r.sum, l.suml + r.suml + l.sum * r.size, l.sumr + r.sumr + r.sum * l.size,
l.suma + r.suma + l.sumr * r.size + r.suml * l.size};
}
int n, m, l, r, c, lc[Node], rc[Node], cnt;
ll tri
, tp
, tag[Node], sum[Node]; //triangular_pyramidal
char op[20];
void build(int i, int l, int r) {
tr[i].size = r - l + 1;
if (l == r) return;
build(lc[i] = ++cnt, l, (l + r) / 2);
build(rc[i] = ++cnt, (l + r) / 2 + 1, r);
}
void chg(int i, int l, int r, int L, int R, ll c);
void push(int i, int l, int r) {
if (!tag[i]) return;
chg(lc[i], l, (l + r) / 2, l, (l + r) / 2, tag[i]);
chg(rc[i], (l + r) / 2 + 1, r, (l + r) / 2 + 1, r, tag[i]);
tag[i] = 0;
}
void chg(int i, int l, int r, int L, int R, ll c) {
if (l > R || r < L) return;
if (l >= L && r <= R) {
tag[i] += c;
tr[i].sum  += c * tr[i].size;
tr[i].suml += c * tri[tr[i].size];
tr[i].sumr += c * tri[tr[i].size];
tr[i].suma += c * tp[tr[i].size];
return;
}
push(i, l, r);
chg(lc[i], l, (l + r) / 2, L, R, c);
chg(rc[i], (l + r) / 2 + 1, r, L, R, c);
tr[i] = tr[lc[i]] + tr[rc[i]];
}
rec qry(int i, int l, int r, int L, int R) {
if (l == L && r == R) return tr[i];
push(i, l, r);
int mid = (l + r) / 2;
if (R <= mid) return qry(lc[i], l, mid, L, R);
if (L >  mid) return qry(rc[i], mid + 1, r, L, R);
return qry(lc[i], l, mid, L, mid) + qry(rc[i], mid + 1, r, mid + 1, R);
}
ll gcd(ll a, ll b) {return b == 0 ? a : gcd(b, a % b);}
int main() {
read(n); read(m); n--;
cnt = 1; build(1, 1, n);
for (int i = 1; i <= n; i++)
tri[i] = (ll)i * (i + 1) / 2,
tp[i] = tp[i - 1] + tri[i];
while (m--) {
scanf("%s", op); read(l); read(r); r--;
if (op[0] == 'C')
read(c), chg(1, 1, n, l, r, c);
else {
ll ans = qry(1, 1, n, l, r).suma, div = (ll)(r - l + 2) * (r - l + 1) / 2, g = gcd(ans, div);
printf("%lld/%lld\n", ans / g, div / g);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树