BZOJ 2752: [HAOI2012]高速公路(road)(线段树)
解题思路
对于一段区间考虑每条边的贡献,即\(ans=\sum\limits_{i=l}^{r-1}(i-l+1)*(r-i)*w(i)\),把这个暴力展开,得到一个关于\(i\)的多项式,然后发现只需要维护\(\sum a(i)\),\(\sum a(i)*i\)和\(\sum a(i)*i^2\),线段树维护即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define int long long
using namespace std;
const int N=100005;
typedef long long LL;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f?x:-x;
}
int n,m;
LL sum0[N<<2],sum1[N<<2],sum2[N<<2];
LL tag0[N<<2],tag1[N<<2],tag2[N<<2];
LL a1[N],a2[N];
inline void pushdown(int x,int l,int r){
int mid=(l+r)>>1;
if(tag0[x]){
sum0[x<<1]+=tag0[x]*(mid-l+1);
sum0[x<<1|1]+=tag0[x]*(r-mid);
tag0[x<<1]+=tag0[x]; tag0[x<<1|1]+=tag0[x];
tag0[x]=0;
}
if(tag1[x]){
sum1[x<<1]+=tag1[x]*(a1[mid]-a1[l-1]);
sum1[x<<1|1]+=tag1[x]*(a1[r]-a1[mid]);
tag1[x<<1]+=tag1[x]; tag1[x<<1|1]+=tag1[x];
tag1[x]=0;
}
if(tag2[x]){
sum2[x<<1]+=tag2[x]*(a2[mid]-a2[l-1]);
sum2[x<<1|1]+=tag2[x]*(a2[r]-a2[mid]);
tag2[x<<1]+=tag2[x]; tag2[x<<1|1]+=tag2[x];
tag2[x]=0;
}
}
void update(int x,int l,int r,int L,int R,int k){
if(L<=l && r<=R) {
sum0[x]+=(r-l+1)*k; tag0[x]+=k;
sum1[x]+=(LL)(a1[r]-a1[l-1])*k; tag1[x]+=k;
sum2[x]+=(LL)(a2[r]-a2[l-1])*k; tag2[x]+=k;
return ;
}
int mid=(l+r)>>1;pushdown(x,l,r);
if(L<=mid) update(x<<1,l,mid,L,R,k);
if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
sum0[x]=sum0[x<<1]+sum0[x<<1|1];
sum1[x]=sum1[x<<1]+sum1[x<<1|1];
sum2[x]=sum2[x<<1]+sum2[x<<1|1];
}
LL query0(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return sum0[x];
int mid=(l+r)>>1; LL ret=0; pushdown(x,l,r);
if(L<=mid) ret+=query0(x<<1,l,mid,L,R);
if(mid<R) ret+=query0(x<<1|1,mid+1,r,L,R);
return ret;
}
LL query1(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return sum1[x];
int mid=(l+r)>>1; LL ret=0; pushdown(x,l,r);
if(L<=mid) ret+=query1(x<<1,l,mid,L,R);
if(mid<R) ret+=query1(x<<1|1,mid+1,r,L,R);
return ret;
}
LL query2(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return sum2[x];
int mid=(l+r)>>1; LL ret=0; pushdown(x,l,r);
if(L<=mid) ret+=query2(x<<1,l,mid,L,R);
if(mid<R) ret+=query2(x<<1|1,mid+1,r,L,R);
return ret;
}
LL gcd(LL x,LL y){
if(!y) return x;
return gcd(y,x%y);
}
signed main(){
n=rd(),m=rd();
for(int i=1;i<n;i++) a1[i]=a1[i-1]+i;
for(int i=1;i<n;i++) a2[i]=a2[i-1]+(LL)i*i;
char c; int l,r,k; LL ans,now,GCD;
while(m--){
c=getchar(); while(c!='C' && c!='Q') c=getchar();
if(c=='C'){
l=rd(),r=rd()-1,k=rd();
update(1,1,n,l,r,k);
}
else {
l=rd(),r=rd()-1; now=(r-l+2)*(r-l+1)/2;
ans=-query2(1,1,n,l,r)+query1(1,1,n,l,r)*(l+r)-query0(1,1,n,l,r)*(l*r+l-r-1);
GCD=gcd(ans,now); ans/=GCD; now/=GCD;
printf("%lld/%lld\n",ans,now);
}
}
return 0;
}