码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj-2752 高速公路 road

时间:2015-08-17 23:43:21      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:bzoj   线段树   

题意:

给出一个n个结点,n-1条边的链,边权初始为0;

m次操作,操作有两种:

1. C:区间[l,r]的边权加上或减去一个数;

2. Q:查询区间随机取不相同两点之间的期望长度;


题解:

区间加减之类的东西显然是线段树的应用,恰巧这道题就在链上;

主要这题还是维护第二问的东西;

区间[l,r]的选路方式共有(r-l+1)*(r-l)/2这些种,那么只要求出所有路径总长度就好了;

对每一条路x来考虑的话,这条路被选的条件是同时选了左面的点和右面的点;

假设这条路的权值是val[x],那么这条路对答案的贡献就是 左面点数*右面点数*val[x];

问题在于如何用线段树实现对此的向上/向下更新;

向下更新的话,长度为n的区间所有数同时减去一个v的话,答案会变化 v*n(n+1)(n+2)/6 这个值;

其实就是1*4+2*3+3*2+4*1这东西的求和公式= =

而向上更新则是两个区间的合并,对每条路考虑左右增加的点数;

那左区间所有路其实都是在右面增加了 右面路径数 这样多的点;

对答案的影响就是 1*val[1]+2*val[2]+3*val[3]... 再乘一个点数;

那么设这东西为L,利用区间和也可以快速维护这东西;

右区间同理,维护R处理就可以了;

query函数有些糟糕,因为需要向上传四个参数,还要搞一个合并;

然后我比较懒所以直接用pair乱搞。。那段区间合并看着就蛮高能的。。

long long没开够WA了一发,全改成long long就A了;

具体原因不查了= =反正这东西似乎不重要?


代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 140142
#define pr pair<ll,ll>
#define par pair<pr,pr>
#define lson l,mid,no<<1
#define rson mid+1,r,no<<1|1
using namespace std;
typedef long long ll;
ll sum[N<<2],ans[N<<2],L[N<<2],R[N<<2],cov[N<<2];
char str[10];
ll gcd(ll a,ll b)
{
	ll t=a%b;
	while(t)
	{
		a=b,b=t;
		t=a%b;
	}
	return b;
}
void Pushup(ll no,ll len)
{
	sum[no]=sum[no<<1]+sum[no<<1|1];
	L[no]=L[no<<1]+L[no<<1|1]+sum[no<<1|1]*(len-(len>>1));
	R[no]=R[no<<1]+R[no<<1|1]+sum[no<<1]*(len>>1);
	ans[no]=ans[no<<1]+ans[no<<1|1]+L[no<<1]*(len>>1)+R[no<<1|1]*(len-(len>>1));
}
void change(ll no,ll v,ll n)
{
	cov[no]+=v;
	sum[no]+=v*n;
	L[no]+=n*(n+1)/2*v;
	R[no]+=n*(n+1)/2*v;
	ans[no]+=n*(n+1)*(n+2)/6*v;
}
void Pushdown(ll no,ll len)
{
	if(cov[no])
	{
		change(no<<1,cov[no],len-(len>>1));
		change(no<<1|1,cov[no],len>>1);
		cov[no]=0;
	}
}
void update(ll l,ll r,ll no,ll st,ll en,ll val)
{
	if(st<=l&&r<=en)
		change(no,val,r-l+1);
	else
	{
		ll mid=l+r>>1;
		Pushdown(no,r-l+1);
		if(en<=mid)		update(lson,st,en,val);
		else if(st>mid)	update(rson,st,en,val);
		else	update(lson,st,en,val),update(rson,st,en,val);
		Pushup(no,r-l+1);
	}
}
par query(ll l,ll r,ll no,ll st,ll en)
{
	if(st<=l&&r<=en)
		return par(pr(ans[no],sum[no]),pr(L[no],R[no]));
	else
	{
		ll mid=l+r>>1;
		Pushdown(no,r-l+1);
		if(en<=mid)		return query(lson,st,en);
		else if(st>mid)	return query(rson,st,en);
		else
		{
			ll llen=(st<=l?r-l+1-((r-l+1)>>1):mid-st+1),
				rlen=(en>=r?(r-l+1)>>1:en-mid);
			par lp=query(lson,st,en),rp=query(rson,st,en),ret;
			ret.first.first=lp.first.first+lp.second.first*rlen+rp.first.first+rp.second.second*llen;
			ret.first.second=lp.first.second+rp.first.second;
			ret.second.first=lp.second.first+rp.second.first+rp.first.second*llen;
			ret.second.second=lp.second.second+rp.second.second+lp.first.second*rlen;
			return ret;
		}
	}
}
int main()
{
	ll n,m,i,j,k,l,r;
	ll v,u,d,g;
	scanf("%lld%lld",&n,&m);
	n--;
	for(i=1;i<=m;i++)
	{
		scanf("%s",&str);
		if(str[0]=='C')
		{
			scanf("%lld%lld%lld",&l,&r,&v);
			update(1,n,1,l,r-1,v);
		}
		else
		{
			scanf("%lld%lld",&l,&r);
			u=query(1,n,1,l,r-1).first.first;
			d=(r-l+1)*(r-l)/2;
			g=gcd(u,d);
			printf("%lld/%lld\n",u/g,d/g);
		}
	}
	return 0;
}




bzoj-2752 高速公路 road

标签:bzoj   线段树   

原文地址:http://blog.csdn.net/ww140142/article/details/47733137

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!