HAOI2012 高速公路
不开long long
见祖宗系列
很自然的想法是求出所有区间的价值然后除区间个数
怎么求区间价值?
设数\(x\)的位置为\(p\),则\(x\)为\([l,r]\)中所有区间的价值做出了\((r−p+1) \times (p−l+1)\)次贡献(乘法原理)
将这个式子拆开,就是\((r−l+1−r\times l)\times x \times p^2+(r+l)\times x \times p − x\)
然后用线段树维护一下\(x \times p ^ 2 , x \times p\)和\(x\)就可以了
最后将这个值除以区间个数就好了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define ls p << 1
#define rs p << 1 | 1
#define mid ((l + r) >> 1)
using namespace std;
LL read() {
LL k = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
k = k * 10 + c -48, c = getchar();
return k * f;
}
char read_c() {
char c = getchar();
while(c != 'C' && c != 'Q') c = getchar();
return c;
}
LL calc(bool opt, LL l, LL r) {
if(opt) // 维护 x*p
return (l+r) * (r-l+1) / 2;
else {
l -= 1; // 维护 x*p*p
return (r * (r+1) * ((r<<1)+1) / 6) - (l * (l+1) * ((l<<1)+1) / 6);
}
}
struct zzz {
LL s1, s2, s3;
void operator += (const zzz &y) & { //重载运算符,可以直接用 += 相加
s1 += y.s1, s2 += y.s2, s3 += y.s3;
return ;
}
}tree[100010 << 2];
LL tag[100010 << 2];
void up(LL p) {
tree[p].s1 = tree[ls].s1 + tree[rs].s1;
tree[p].s2 = tree[ls].s2 + tree[rs].s2;
tree[p].s3 = tree[ls].s3 + tree[rs].s3;
}
void down(LL p, LL l, LL r) {
LL k = tag[p];
tree[ls].s1 += (mid-l+1) * k;
tree[ls].s2 += calc(1, l, mid) * k;
tree[ls].s3 += calc(0, l, mid) * k;
tree[rs].s1 += (r-mid) * k;
tree[rs].s2 += calc(1, mid+1, r) * k;
tree[rs].s3 += calc(0, mid+1, r) * k;
tag[ls] += k; tag[rs] += k; tag[p] = 0;
}
void update(LL l, LL r, LL p, LL nl, LL nr, LL k) {
if(nl <= l && nr >= r) {
tree[p].s1 += (r-l+1) * k;
tree[p].s2 += calc(1, l, r) * k;
tree[p].s3 += calc(0, l, r) * k;
tag[p] += k; return ;
}
down(p, l, r);
if(nl <= mid) update(l, mid, ls, nl, nr, k);
if(nr > mid) update(mid+1, r, rs, nl, nr, k);
up(p);
}
zzz query(LL l, LL r, LL p, LL nl, LL nr) {
zzz ans = (zzz){0, 0, 0};
if(nl <= l && nr >= r)
return tree[p];
down(p, l, r);
if(nl <= mid)
ans += query(l, mid, ls, nl, nr);
if(nr > mid)
ans += query(mid+1, r, rs, nl, nr);
up(p);
return ans;
}
LL gcd(LL x, LL y) {
return x % y == 0 ? y : gcd(y, x % y);
}
int main() {
LL n = read(), m = read();
for(LL i = 1; i <= m; ++i) {
char opt = read_c(); LL l = read(), r = read() - 1;
if(opt == 'C') {
LL k = read();
update(1, n, 1, l, r, k);
}
else {
zzz x = query(1, n, 1, l, r);
LL ans = (r-l+1-r*l) * x.s1 + (r+l) * x.s2 - x.s3;
LL b = (r-l+2) * (r-l+1) / 2;
LL g = gcd(ans, b); //约分
printf("%lld/%lld\n", ans/g, b/g);
}
}
return 0;
}