[HAOI2012]高速公路

II.[HAOI2012]高速公路

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

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

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

sum:区间和

len:区间长度

tag:区间懒标记

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

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

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

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

时间复杂度O(nlogn)

代码:

#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 @   Troverld  阅读(42)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示