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;
}
posted @ 2019-01-18 09:47  Monster_Qi  阅读(147)  评论(0编辑  收藏  举报