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;
}
posted @ 2019-10-17 20:14  wuhan2005  阅读(102)  评论(0编辑  收藏  举报