bzoj 2752 [HAOI2012]高速公路(road) 线段树

题面

题目传送门

解法

先把边转化成区间

其实我们只要计算\(\sum_{i=l}^{r-1}\sum_{j=i+1}^{r}sum(i,j)\)

把式子拆开,可以得到\((l+r)\sum w_i*i-(l+1)(r-1)\sum w_i-\sum w_i*i^2\)

用线段树分别维护这三个值即可

时间复杂度:\(O(m\ log\ n)\)

代码

#include <bits/stdc++.h>
#define int long long
#define N 100010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
	x = 0; int f = 1; char c = getchar();
	while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
int s[N];
struct Info {int x, y, z;};
Info operator + (Info a, Info b) {return (Info) {a.x + b.x, a.y + b.y, a.z + b.z};}
struct SegmentTree {
	struct Node {
		int l, r, s1, s2, s3, del;
	} t[N * 4];
	void build(int k, int l, int r) {
		t[k] = (Node) {l, r, 0, 0, 0, 0};
		if (l == r) return; int mid = (l + r) >> 1;
		build(k << 1, l, mid); build(k << 1 | 1, mid + 1, r);
	}
	void Add(int k, int v) {
		int l = t[k].l, r = t[k].r;
		t[k].s1 += (r - l + 1) * v;
		t[k].s2 += (l + r) * (r - l + 1) / 2 * v;
		t[k].s3 += (s[r] - s[l - 1]) * v;
		t[k].del += v;
	}
	void update(int k) {
		t[k].s1 = t[k << 1].s1 + t[k << 1 | 1].s1;
		t[k].s2 = t[k << 1].s2 + t[k << 1 | 1].s2;
		t[k].s3 = t[k << 1].s3 + t[k << 1 | 1].s3;
	}
	void pushdown(int k) {
		int x = t[k].del; t[k].del = 0;
		Add(k << 1, x), Add(k << 1 | 1, x);
	}
	void modify(int k, int L, int R, int v) {
		int l = t[k].l, r = t[k].r;
		if (L <= l && r <= R) {Add(k, v); return;}
		if (t[k].del) pushdown(k);
		int mid = (l + r) >> 1;
		if (L <= mid && mid < R)
			modify(k << 1, L, mid, v), modify(k << 1 | 1, mid + 1, R, v);
		if (R <= mid) modify(k << 1, L, R, v);
		if (L > mid) modify(k << 1 | 1, L, R, v);
		update(k);
	}
	Info query(int k, int L, int R) {
		int l = t[k].l, r = t[k].r;
		if (L <= l && r <= R) return (Info) {t[k].s1, t[k].s2, t[k].s3};
		if (t[k].del) pushdown(k); int mid = (l + r) >> 1;
		if (R <= mid) return query(k << 1, L, R);
		if (L > mid) return query(k << 1 | 1, L, R);
		return query(k << 1, L, mid) + query(k << 1 | 1, mid + 1, R);
	}
} T;
int gcd(int x, int y) {
	if (y == 0) return x;
	return gcd(y, x % y);
}
main() {
	int n, m; read(n), read(m); T.build(1, 1, n - 1);
	for (int i = 1; i <= n; i++) s[i] = s[i - 1] + i * i;
	while (m--) {
		char c = getchar();
		while (!isalpha(c)) c = getchar();
		if (c == 'C') {
			int l, r, v; read(l), read(r), read(v);
			T.modify(1, l, r - 1, v);
		} else {
			int l, r; read(l), read(r);
			Info tmp = T.query(1, l, r - 1);
			int x = -(l - 1) * r * tmp.x + (l + r - 1) * tmp.y - tmp.z, y = (r - l + 1) * (r - l) / 2;
			int t = gcd(x, y); cout << x / t << '/' << y / t << "\n";
		}
	}
	return 0;
}

posted @ 2018-08-14 18:50  谜のNOIP  阅读(163)  评论(0编辑  收藏  举报