P2221 [HAOI2012]高速公路
\(n-1\)条边,查询点\((l,r)l<r\)相当于边\((l,r-1)\)
,\(dis_{i,j}\)表示边\(i\)~\(j\)权之和
每次查询边\((l,r)\)
\(ans=\dfrac{\sum\limits_{i=l}^r\sum\limits_{j=i}^rdis_{i,j}}{C_{r-l+1}^2}=\dfrac{\sum\limits_{i=l}^ra_{i}(r-i+1)(i-l+1)}{((r+1)-l)((r+1)-l+1)}\)
我们来看上面这部分,拆开后
\(\sum\limits_{i=l}^ra_{i}(ri-rl+r-i^2+il-i+i-l+1)\)
\(\sum\limits_{i=l}^ra_{i}(ri-rl+r-i^2+il-l+1)\)
\(\sum\limits_{i=l}^ra_{i}(-i^2+ri+il-rl+r-l+1)\)
\(\sum\limits_{i=l}^ra_{i}((-i^2)+i(l+r)+(r+1-rl-l)\)
\(\sum\limits_{i=l}^ra_{i}(r+1-rl-l)+\sum\limits_{i=l}^ra_{i}(i(l+r))+\sum\limits_{i=l}^ra_{i}((-i^2)\)
线段树维护\(\sum\limits_{i=l}^ra_{i},\sum\limits_{i=l}^ra_{i}*i,\sum\limits_{i=l}^ra_{i}*i*i\)三个值就行了
现在考虑区间修改时怎么拆开上面的式子,假设\((l,r)\)加上\(val\)
\(sum1+=val(r-l+1)\)
\(sum2+=val[(l+r)(r-l+1)/2]\)
维护\(sum3\)要用到一个常用公式了,不会自行百度\(\sum\limits_{i=1}^ni^2=\dfrac {n(n+1)(2n+1)}{6}\)
\(sum3+=val\dfrac {r(r+1)(2r+1)-(l-1)[(l-1)+1][2(l-1)+1]}{6}\)
其他的就是类似模板的东西了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e7+1;
inline LL Read(){
LL x=0,f=1; char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
struct node{
LL lazy;
LL sum1,sum2,sum3;
LL son[2];
}tree[maxn];
LL n,m,nod,root;
inline void Update(LL now){
LL son0=tree[now].son[0]; LL son1=tree[now].son[1];
tree[now].sum1=tree[son0].sum1+tree[son1].sum1,
tree[now].sum2=tree[son0].sum2+tree[son1].sum2,
tree[now].sum3=tree[son0].sum3+tree[son1].sum3;
}
inline void Pushdown(LL now,LL l,LL r){
if(!tree[now].lazy)
return;
LL val=tree[now].lazy;
if(!tree[now].son[0]) tree[now].son[0]=++nod; LL son0=tree[now].son[0];
if(!tree[now].son[1]) tree[now].son[1]=++nod; LL son1=tree[now].son[1];
LL mid=(l+r)>>1; LL l1=l,r1=mid,l2=mid+1,r2=r;
tree[son0].lazy+=val,
tree[son0].sum1+=(r1-l1+1)*val,
tree[son0].sum2+=(l1+r1)*(r1-l1+1)/2*val,
tree[son0].sum3+=((r1*(r1+1)*(2*r1+1)-(l1-1)*((l1-1)+1)*(2*(l1-1)+1))/6)*val,
tree[son1].lazy+=val,
tree[son1].sum1+=(r2-l2+1)*val,
tree[son1].sum2+=(l2+r2)*(r2-l2+1)/2*val,
tree[son1].sum3+=((r2*(r2+1)*(2*r2+1)-(l2-1)*((l2-1)+1)*(2*(l2-1)+1))/6)*val,
tree[now].lazy=0;
}
void Add(LL &now,LL l,LL r,LL lt,LL rt,LL val){
if(!now)
now=++nod;
if(lt<=l&&rt>=r){
tree[now].lazy+=val,
tree[now].sum1+=(r-l+1)*val,
tree[now].sum2+=(l+r)*(r-l+1)/2*val,
tree[now].sum3+=((r*(r+1)*(2*r+1)-(l-1)*((l-1)+1)*(2*(l-1)+1))/6)*val;
return;
}
Pushdown(now,l,r);
LL mid=(l+r)>>1;
if(lt<=mid)
Add(tree[now].son[0],l,mid,lt,rt,val);
if(rt>mid)
Add(tree[now].son[1],mid+1,r,lt,rt,val);
Update(now);
}
LL Query(LL &now,LL l,LL r,LL lt,LL rt){
if(!now)
now=++nod;
if(lt<=l&&rt>=r)
return (rt-lt+1-lt*rt)*tree[now].sum1+(rt+lt)*tree[now].sum2-tree[now].sum3;
Pushdown(now,l,r);
LL mid=(l+r)>>1,sum=0;
if(lt<=mid)
sum+=Query(tree[now].son[0],l,mid,lt,rt);
if(rt>mid)
sum+=Query(tree[now].son[1],mid+1,r,lt,rt);
return sum;
}
LL Gcd(LL x,LL y){
if(!y)
return x;
return Gcd(y,x%y);
}
int main(){
n=Read()-1,m=Read();
while(m--){
char c; scanf(" %c",&c);
LL l=Read(),r=Read()-1;
if(c=='C'){
LL val=Read();
Add(root,1,n,l,r,val);
}else{
LL mu=Query(root,1,n,l,r),zi=((r+1)-l)*((r+1)-l+1)/2;
LL g=Gcd(mu,zi);
printf("%lld/%lld\n",mu/g,zi/g);
}
}
return 0;
}/*
*/