luoguP2221 [HAOI2012]高速公路
首先便于计算,我们可以将每一条边缩成一个点,于是右端点\(r\)需要减\(1\).
从\(a\)行驶到\(b\)将期望花费
\[\begin{align}
ans=\dfrac{Ans}{C^{2}_{r-l+2}}
\end{align}
\]
我们可以对于每一条边统计它被算了多少次.
\[\begin{align}
\therefore Ans&=\sum^r_{i=l}v[i]*(i-l+1)(r-i+1)\\
&=\sum^r_{i=l}v[i]*[-i^2+(l+r)*i+(1+r)(1-l)]\\
&=-\sum^r_{i=l}v[i]*i^2+(l+r)\sum^r_{i=l}v[i]*i-(r+1)(l-1)\sum^r_{i=l}v[i]
\end{align}
\]
于是我们只需要在线段树中维护三个值.
\[\begin{align}
tr[0][x]&=\sum^{x.r}_{i=x.l}a[i]\\
tr[1][x]&=\sum^{x.r}_{i=x.l}a[i]*i\\
tr[2][x]&=\sum^{x.r}_{i=x.l}a[i]*i^2\\
\end{align}
\]
合并非常简单.
\[\begin{align}
tr[0][x]&=tr[0][x<<1]+tr[0][x<<1|1]\\
tr[1][x]&=tr[1][x<<1]+tr[1][x<<1|1]\\
tr[2][x]&=tr[2][x<<1]+tr[2][x<<1|1]\\
\end{align}
\]
但是如何修改呢?
对于\(tr[0]\):
\[\begin{align}
\Delta tr[0][x]&=\sum^{x.r}_{i=x.l}\Delta v[i]\\
&=k\sum^{x.r}_{i=x.l}1\\
&=k*(x.r-x.l+1)
\end{align}
\]
对于\(tr[1]\):
\[\begin{align}
\Delta tr[1][x]&=\sum^{x.r}_{i=x.l}\Delta v[i]*i\\
&=k\sum^{x.r}_{i=x.l}i\\
&=k*(x.r+x.l)*(x.r-x.l+1)/2
\end{align}
\]
对于\(tr[2]\):
\[\begin{align}
\Delta tr[2][x]&=\sum^{x.r}_{i=x.l}\Delta v[i]*i^2\\
&=k\sum^{x.r}_{i=x.l}i^2\\
&=k(\sum^{x.r}_{i=1}i^2-\sum^{x.l-1}_{i=1}i^2)
\end{align}
\]
相信大家都学过平方相加的公式:
\[\begin{align}
1^2+2^2+......+n^2=\frac{n(n+1)(2n+1)}{6}
\end{align}
\]
没学过的可以康康
\[\begin{align}
\therefore\Delta tr[2][x]&=\frac{k(x.r(x.r+1)(2x.r+1)-(x.l-1)x.l(2x.l-1))}{6}
\end{align}
\]
最后:
一定要开longlong!
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
typedef long long ll;
const int O = 1e5 + 10;
template<class TT>
il TT read() {
TT o = 0,fl = 1; char ch = getchar();
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') fl = -1, ch = getchar();
while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
return fl * o;
}
char ch[2];
int n, m;
ll xx, yy, zz;
class SegmentTree {
private:
ll tr[6][O << 2], lazy[O << 2];
il void pushup(int x) {
tr[0][x] = tr[0][x << 1] + tr[0][x << 1 | 1];
tr[1][x] = tr[1][x << 1] + tr[1][x << 1 | 1];
tr[2][x] = tr[2][x << 1] + tr[2][x << 1 | 1];
}
il void work(int delta, int x, int len) {
tr[0][x] += 1ll * delta * len;
tr[1][x] += 1ll * delta * tr[4][x];
tr[2][x] += 1ll * delta * tr[5][x];
lazy[x] += delta;
}
il void pushdown(int x, int l, int r) {
if(!lazy[x]) return ;
int mid = l + r >> 1;
work(lazy[x], x << 1, mid - l + 1);
work(lazy[x], x << 1 | 1, r - mid);
lazy[x] = 0;
}
public:
il void Build(int x, int l, int r) {
if (l == r) {
tr[4][x] = l;
tr[5][x] = 1ll * l * l;
return ;
}
int mid = l + r >> 1;
Build(x << 1, l, mid);
Build(x << 1 | 1, mid + 1, r);
tr[4][x] = tr[4][x << 1] + tr[4][x << 1 | 1];
tr[5][x] = tr[5][x << 1] + tr[5][x << 1 | 1];
}
il void Modify(int x, int l, int r, int L, int R, int delta) {
if (l > R || L > r) return ;
if (L <= l && r <= R) return work(delta, x, r - l + 1);
pushdown(x, l, r);
int mid = l + r >> 1;
Modify(x << 1, l, mid, L, R, delta);
Modify(x << 1 | 1, mid + 1, r, L, R, delta);
pushup(x);
}
il void Query(int x, int l, int r, int L, int R) {
if (l > R || L > r) return ;
if (L <= l && r <= R) {
xx += tr[0][x];
yy += tr[1][x];
zz += tr[2][x];
return ;
}
pushdown(x, l, r);
int mid = l + r >> 1;
Query(x << 1, l, mid, L, R);
Query(x << 1 | 1, mid + 1, r, L, R);
}
}st;
int main() {
n = gi(), m = gi();
st.Build(1, 1, n);
while (m--) {
scanf("%s", ch);
int l = gi(), r = gi() - 1;
if (ch[0] == 'C') st.Modify(1, 1, n, l, r, gi());
else {
xx = yy = zz = 0;
st.Query(1, 1, n, l, r);
ll X = 1ll * (l + r) * yy + 1ll * (r + 1) * (1 - l) * xx - zz;
ll Y = 1ll * (r - l + 2) * (r - l + 1) >> 1, g = __gcd(X, Y);
X /= g, Y /= g;
printf("%lld/%lld\n", X, Y);
}
}
return 0;
}