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;
}