#线段树#洛谷 2221 [HAOI2012]高速公路 分析 代码

题目


首先把收费站之间化为点,那这样即是区间加和区间查询,
考虑求的应该是

[frac{sum a[i]*(r-i+1)*(i-l+1)}{C(r-l+2,2)} ]

分子可以拆成

[a[i]*(l+r)*i-a[i]*(r+1)*(l-1)-a[i]*i*i ]

关键是要维护(sum a[i],sum a[i]*i,sum a[i]*i*i)
这个可以用(sum i=(i+1)*i/2,sum i^2=i*(i+1)*(2*i+1)/6)实现


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=100011; typedef long long lll;
struct three{lll w0,w1,w2;}w[N<<2]; int lazy[N<<2],n;
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline void print(lll ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline three pup(three k1,three k2){return (three){k1.w0+k2.w0,k1.w1+k2.w1,k1.w2+k2.w2};}
inline lll C(int n){return 1ll*n*(n-1)>>1;}
inline lll calc(int n){return 1ll*n*(n+1)*(n<<1|1)/6;}
inline void ptag(int k,int l,int r,int z){
	w[k].w0+=(r-l+1)*z,w[k].w1+=(C(r+1)-C(l))*z,
	w[k].w2+=(calc(r)-calc(l-1))*z,lazy[k]+=z;
}
inline void update(int k,int l,int r,int x,int y,int z){
	if (l==x&&r==y){ptag(k,l,r,z); return;}
	rr int mid=(l+r)>>1;
	if (lazy[k]) ptag(k<<1,l,mid,lazy[k]),ptag(k<<1|1,mid+1,r,lazy[k]),lazy[k]=0;
	if (y<=mid) update(k<<1,l,mid,x,y,z);
	else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
	    else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
	w[k]=pup(w[k<<1],w[k<<1|1]);
}
inline three query(int k,int l,int r,int x,int y){
	if (l==x&&r==y) return w[k];
	rr int mid=(l+r)>>1;
	if (lazy[k]) ptag(k<<1,l,mid,lazy[k]),ptag(k<<1|1,mid+1,r,lazy[k]),lazy[k]=0;
	if (y<=mid) return query(k<<1,l,mid,x,y);
	else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
	    else return pup(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
signed main(){
	n=iut()-1;
	for (rr int m=iut();m;--m){
		rr char c=getchar();
		while (!isalpha(c)) c=getchar();
		rr int l=iut(),r=iut()-1;
		if (l>r) continue;
		if (c=='C') update(1,1,n,l,r,iut());
		else if (c=='Q'){
			rr three Ans=query(1,1,n,l,r);
			rr lll ans=Ans.w0*(r+1)*(1-l)+Ans.w1*(l+r)-Ans.w2;
			rr lll ans2=C(r-l+2),GCD=__gcd(ans,ans2);
			print(ans/GCD),putchar('/'),print(ans2/GCD),putchar(10);
		}
	}
	return 0;
}