[HAOI2012]高速公路

II.[HAOI2012]高速公路

本题已经在我的任务列表里挂了1年多了

我们将这里的“期望”转成“\(\dfrac{\text{区间中任意两点间距离之和}}{\text{区间中选取两点的方案数}}\)。然后,我们考虑使用线段树维护区间中任意两点间距离之和。

在每个节点上,我们维护如下东西:

\(sum\):区间和

\(len\):区间长度

\(tag\):区间懒标记

\(pre\):区间中每个点到区间中第一个点的距离之和

\(suf\):区间中每个点到区间中最后一个点的距离之和

\(all\):区间中任意两点间距离之和

这个可以通过简单拼凑得到。

时间复杂度\(O(n\log n)\)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; 
int n,m;
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1)
#define C(x) (1ll*((x)+1)*(x)/2)
struct SegTree{
	int sum,len,tag;
	ll all,pre,suf;
	SegTree(){sum=len=tag=all=pre=suf=0;}
	friend SegTree operator +(const SegTree &x,const SegTree &y){
		SegTree z;
		z.len=x.len+y.len;
		z.sum=x.sum+y.sum;
		z.pre=x.pre+y.pre+1ll*x.sum*y.len;
		z.suf=y.suf+x.suf+1ll*y.sum*x.len;
		z.all=x.all+y.all+x.suf*y.len+y.pre*x.len;
		return z;
	}
	void ADD(int x){
		sum+=x*len;
		tag+=x;
		pre+=C(len)*x;
		suf+=C(len)*x;
		all+=1ll*len*(len+1)*(len+2)/6*x;
	}
}seg[400100];
#define pushdown(x) seg[lson].ADD(seg[x].tag),seg[rson].ADD(seg[x].tag),seg[x].tag=0
void build(int x,int l,int r){
	seg[x].len=r-l;
	if(l+1==r)return;
	build(lson,l,mid),build(rson,mid,r);
}
void modify(int x,int l,int r,int L,int R,int val){
	if(l>=R||r<=L)return;
	if(L<=l&&r<=R){seg[x].ADD(val);return;}
	pushdown(x),modify(lson,l,mid,L,R,val),modify(rson,mid,r,L,R,val),seg[x]=seg[lson]+seg[rson];
}
SegTree query(int x,int l,int r,int L,int R){
	if(l>=R||r<=L)return SegTree();
	if(L<=l&&r<=R)return seg[x];
	pushdown(x);
	return query(lson,l,mid,L,R)+query(rson,mid,r,L,R);
}
void iterate(int x,int l,int r){
	printf("[%d,%d):%d,%lld,%lld,%lld\n",l,r,seg[x].sum,seg[x].pre,seg[x].suf,seg[x].all);
	if(l+1<r)pushdown(x),iterate(lson,l,mid),iterate(rson,mid,r),seg[x]=seg[lson]+seg[rson];
	printf("[%d,%d):%d,%lld,%lld,%lld\n",l,r,seg[x].sum,seg[x].pre,seg[x].suf,seg[x].all);
}
char c[10];
int main(){
	scanf("%d%d",&n,&m),build(1,1,n);
	for(int i=1,l,r,v;i<=m;i++){
		scanf("%s%d%d",c,&l,&r);
		if(c[0]=='C')scanf("%d",&v),modify(1,1,n,l,r,v);
		else{
			ll x=query(1,1,n,l,r).all,y=C(r-l);
			ll GCD=gcd(y,x);
			printf("%lld/%lld\n",x/GCD,y/GCD);
		}
//		iterate(1,1,n);
	}
	return 0;
} 

posted @ 2021-04-02 15:16  Troverld  阅读(41)  评论(0编辑  收藏  举报