HAOI2012 高速公路

夏佑 | XiaU

一道非常好的线段树题。

Sol.

优先想到线段树,考虑怎么维护。

记第 \(i\) 到第 \(i+1\) 条边为第 \(i\) 条边,将问题转化成维护 \(n-1\) 个数。

那么,我们维护一个前缀和 \(sum\),根据题意:

\[ Ans=\frac{\sum\limits_{i=l}^{r}\sum\limits_{j=l}^{r}sum_j-sum_i}{\binom{r-l+1}{2}}(i\neq j) \]

下面的东西很好算,重点是上面的东西怎么维护。

我们把上面的东西记作 \(ans\),考虑枚举每条边被计算的次数,可以理解成枚举每个点左右两条路。

所以:

\[ \begin{split} ans &=\sum\limits_{i=l}^{r}a_i\times (r-i+1)(i-l+1)\\ &=\sum\limits_{i=l}^{r}a_i\times (ir-lr+r-i^2+il-i+i-l+1)\\ &=\sum\limits_{i=l}^{r}a_i\times (-i^2+(l+r)i-lr+r-l+1)\\ &=-\sum\limits_{i=l}^{r}a_i\times i^2+(l+r)\sum\limits_{i=l}^{r}a_i\times i+(r-l-lr+1)\sum\limits_{i=l}^{r}a_i \end{split} \]

现在需要维护 \(sum_1=\sum_{i=l}^{r}a_i\times i^2\)\(sum_2=\sum_{i=l}^{r}a_i\times i\)\(sum_3=\sum_{i=l}^{r}a_i\)

即变成:

\[ans=-sum1+(l+r)sum2+(r-l-lr+1)sum3\]

考虑 pushup 的时候,直接相加就可以了。

考虑在区间 \([L,R]\) 加上一个 \(x\) 的时候怎么做:

\[ \begin{split} sum_3' &= \sum\limits_{i=L}^{R}(a_i+x)\\ &= (R-L+1)x+\sum\limits_{i=L}^{R}a_i\\ &= (R-L+1)x+sum_3\\ \Delta sum_3 &= (R-L+1)x \end{split} \]

直接维护。

\[ \begin{split} sum_2' &= \sum\limits_{i=L}^{R}i(a_i+x)\\ &= \sum\limits_{i=L}^{R}i\times a_i+\sum\limits_{i=L}^{R}ix\\ &= \sum\limits_{i=L}^{R}i\times a_i+x\sum\limits_{i=L}^{R}i\\ &= x\sum\limits_{i=L}^{R}i+sum_2\\ \Delta sum_2 &= x\sum\limits_{i=L}^{R}i \end{split} \]

维护区间和。

\[ \begin{split} sum_1' &= \sum\limits_{i=L}^{R}i^2(a_i+x)\\ &= \sum\limits_{i=L}^{R}i^2\times a_i+\sum\limits_{i=L}^{R}i^2x\\ &= \sum\limits_{i=L}^{R}i^2\times a_i+x\sum\limits_{i=L}^{R}i^2\\ &= x\sum\limits_{i=L}^{R}i^2+sum_1\\ \Delta sum_1 &= x\sum\limits_{i=L}^{R}i^2 \end{split} \]

维护区间平方和。

最后求期望约分即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include<bits/stdc++.h>
using namespace std;

#define int long long

const int MAXN = 100007;

int n, m;
int ans1, ans2, ans3;

class Tree
{
#define int long long
private:
struct Node
{
int sum1, sum2, sum3, sum4, sum5;
int lazy;
int l, r;
}tree[MAXN << 2];

inline int lc(int k){return k << 1;}

inline int rc(int k){return k << 1 | 1;}

inline void f(int k, int v)
{
tree[k].lazy += v;
tree[k].sum1 += (tree[k].r - tree[k].l + 1) * v;
tree[k].sum2 += v * tree[k].sum5;
tree[k].sum3 += v * tree[k].sum4;
}

inline void pushup(int k)
{
tree[k].sum1 = tree[lc(k)].sum1 + tree[rc(k)].sum1;
tree[k].sum2 = tree[lc(k)].sum2 + tree[rc(k)].sum2;
tree[k].sum3 = tree[lc(k)].sum3 + tree[rc(k)].sum3;
}

inline void pushdown(int k)
{
f(lc(k), tree[k].lazy);
f(rc(k), tree[k].lazy);
tree[k].lazy = 0;
}

public:
void build(int k,int l, int r)
{
tree[k].lazy = 0;
tree[k].l = l;
tree[k].r = r;
if(l == r)
{
tree[k].sum4 = l * l;
tree[k].sum5 = l;
return;
}
int mid = (l + r) >> 1;
build(lc(k), l, mid);
build(rc(k), mid + 1, r);
tree[k].sum4 = tree[lc(k)].sum4 + tree[rc(k)].sum4;
tree[k].sum5 = tree[lc(k)].sum5 + tree[rc(k)].sum5;
}

void update(int k, int L, int R, int v)
{
if(L <= tree[k].l && tree[k].r <= R)
{
f(k, v);
return;
}
pushdown(k);
int mid = (tree[k].l + tree[k].r) >> 1;
if(L <= mid) update(lc(k), L, R, v);
if(R > mid) update(rc(k), L, R, v);
pushup(k);
}

void query(int k, int L, int R)
{
if(L <= tree[k].l && tree[k].r <= R)
{
ans1 += tree[k].sum1;
ans2 += tree[k].sum2;
ans3 += tree[k].sum3;
return;
}
pushdown(k);
int mid = (tree[k].l + tree[k].r) >> 1;
if(L <= mid) query(lc(k), L, R);
if(R > mid) query(rc(k), L, R);
return;
}
};

Tree t;

int gcd(int a, int b)
{
return !b ? a : gcd(b, a % b);
}

signed main()
{
scanf("%lld%lld", &n, &m);
t.build(1, 1, n);
for(int i = 1; i <= m; i++)
{
char op;
int l, r, v;
cin >> op;
scanf("%lld%lld", &l, &r);
r--;
if(op == 'C')
{
scanf("%lld", &v);
t.update(1, l, r, v);
}
else
{
ans1 = ans2 = ans3 = 0;
t.query(1, l, r);
int a, b, c;
a = (r - l + 1 - r * l) * ans1 + (r + l) * ans2 - ans3;
b = (r - l + 2) * (r - l + 1) / 2;
c = gcd(a, b);
//cout << l << r << b;
printf("%lld/%lld\n", a / c, b / c);
}
}
return 0;
}
  • 标题: HAOI2012 高速公路
  • 作者: 夏佑 | XiaU
  • 创建于 : 2022-09-01 00:00:00
  • 更新于 : 2023-09-15 09:14:16
  • 链接: https://oi.xiau.ren/LGP2221/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
此页目录
HAOI2012 高速公路