您的位置:首页 > 其它

bzoj 2752: [HAOI2012]高速公路(road) (线段树)

2017-03-30 11:37 363 查看

题目描述

传送门

题目大意:一个n个点的链,有n-1条路径,每条路径有一个花费。会不定期的对连续路段的花费进行区间修改。

对于给定的l,r(l<r),在[l,r]中任选两个点a,b,那么从a到b将期望花费多少费用呢?

题解

对于路径建立线段树,所以一共有n-1个点。

维护的话有点恶心。

cnt=(r-l+1) 区间点数

size 表示任选两个点有多少种选择

tr 表示区间权值和

delta 区间修改的标记

sum 从区间中任选两个点a,b,所有方案的总花费

ls 区间中的每个点到左端点的路径和

rs 区间中的每个点到右端点的路径和

具体的更新过程还是看代码吧,不是很好说明。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100003
#define LL long long
using namespace std;
struct data{
LL cnt,size,sum,tr,ls,rs,delta;
}a[N*4];
int n,m;
LL base
;
data update(data l,data r)
{
data c; c.delta=0;
c.cnt=l.cnt+r.cnt;
c.size=l.size+r.size+l.cnt*r.cnt;
c.tr=l.tr+r.tr;
c.sum=l.sum+r.sum+l.rs*r.cnt+r.ls*l.cnt;
c.rs=l.rs+r.rs+l.cnt*r.tr;
c.ls=l.ls+r.ls+r.cnt*l.tr;
return c;
}
void build(int now,int l,int r)
{
if (l==r) {
a[now].size=a[now].cnt=1;
return;
}
int mid=(l+r)/2;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
a[now]=update(a[now<<1],a[now<<1|1]);
}
LL calc(LL x){
return x*(x+1)/2;
}
void change(int x,int l,int r,LL val)
{
a[x].tr+=a[x].cnt*val;
a[x].sum+=base[a[x].cnt]*val;
a[x].ls+=calc(a[x].cnt)*val;
a[x].rs+=calc(a[x].cnt)*val;
a[x].delta+=val;
}
void pushdown(int now,int l,int r)
{
int mid=(l+r)/2;
if (a[now].delta) {
change(now<<1,l,mid,a[now].delta);
change(now<<1|1,mid+1,r,a[now].delta);
a[now].delta=0;
}
}
void qjchange(int now,int l,int r,int ll,int rr,LL val)
{
if (ll>rr) return;
if (ll<=l&&r<=rr) {
change(now,l,r,val);
return;
}
int mid=(l+r)/2;
pushdown(now,l,r);
if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,val);
if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,val);
a[now]=update(a[now<<1],a[now<<1|1]);
}
data qjsum(int now,int l,int r,int ll,int rr)
{
if (ll>rr) {
data ans; ans.sum=0;
return ans;
}
if (ll<=l&&r<=rr) return a[now];
int mid=(l+r)/2;
pushdown(now,l,r);
data ans; ans.cnt=0;
if (ll<=mid) ans=qjsum(now<<1,l,mid,ll,rr);
if (rr>mid) {
if (ans.cnt==0) ans=qjsum(now<<1|1,mid+1,r,ll,rr);
else ans=update(ans,qjsum(now<<1|1,mid+1,r,ll,rr));
}
return ans;
}
LL gcd(LL x,LL y)
{
LL r;
while (y) {
r=x%y;
x=y; y=r;
}
return x;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
n--;
base[1]=1;
for (int i=2;i<=n;i++)
base[i]=base[i-1]+calc(i-1)+(LL)i;
build(1,1,n);
for (int i=1;i<=m;i++) {
char s[10]; int x,y; scanf("%s%d%d",s+1,&x,&y);
y--;
if (s[1]=='C') {
int val; scanf("%d",&val);
qjchange(1,1,n,x,y,val);
}
else {
data ans=qjsum(1,1,n,x,y);
LL a=ans.sum; LL b=ans.size;
LL t=gcd(a,b);
a/=t; b/=t;
printf("%lld/%lld\n",a,b);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树