[Luogu 2221] HAOI2012 高速公路

[Luogu 2221] HAOI2012 高速公路

<题目链接>


比较容易看出的线段树题目。

由于等概率,期望便转化为 子集元素和/子集个数。

每一段l..r中,子集元素和为:

\(\sum w_{i}(i-l+1)(r-i)\) //\((i-l+1)(r-i)\)是每个数用到的次数

\(=\sum w_{i}((r-lr)+(l+r-1)i-i^{2})\)

\(=(r-lr)\sum w_{i}+(l+r-1)\sum i\times w_{i}-\sum i^{2}\times w_{i}\)

由此观之,线段树需要维护\(\sum w_{i}\)v[0]\(\sum i\times w_{i}\)v[1]\(\sum i^{2}\times w_{i}\)v[2]

有这样一个神奇的公式:

\(1^{2}+2^{2}+\dots+n^{2}=n(n+1)(2n+1)/6\)

所以,在进行Update操作时,设size=r-l+1,改变量为v

v[0]+=v*size;
v[1]+=v*size*(l+r)>>1;
v[2]+=v*(r*(r+1)*((r<<1)+1)-(l-1)*l*((l<<1)-1))/6LL;

记得开long long以及各种强制转int为long long!隐式类型转换简直天坑。

线段树基础不扎实的我这题调了一天…

#include <cstdio>
#include <cstring>
const int MAXN=100010;
int n,m;
class SegmentTree
{
	public:
		SegmentTree(void)
		{
			memset(s,0,sizeof s);
		}
		void BuildTree(int i,int l,int r)
		{
			s[i].l=l,s[i].r=r;
			if(l==r)
				return;
			int j=i<<1,mid=l+r>>1;
			BuildTree(j,l,mid),BuildTree(j+1,mid+1,r);
		}
		void Add(int i,int l,int r,long long v)
		{
			if(l==s[i].l && r==s[i].r)
			{
				Update(i,v);
				return;
			}
			if(s[i].l!=s[i].r && s[i].lazy)
				PushDown(i);
			int j=i<<1,mid=s[i].l+s[i].r>>1;
			if(r<=mid)
				Add(j,l,r,v);
			else if(l>mid)
				Add(j+1,l,r,v);
			else
				Add(j,l,mid,v),Add(j+1,mid+1,r,v);
			PushUp(i);
		}
		void Ans(long long l,long long r)
		{
			long long t,ans,cnt=(r-l+1)*(r-l)>>1LL,sum[3];
			for(int i=0;i<3;++i)
				sum[i]=Sum(1,l,r-1,i);
			ans=sum[0]*(r-l*r)+sum[1]*(l+r-1)-sum[2];
			t=GCD(ans,cnt);
			printf("%lld/%lld\n",ans/t,cnt/t);
		}
	private:
		struct node
		{
			int l,r;
			long long lazy,v[3];
		}s[MAXN<<2];
		long long GCD(long long x,long long y)
		{
			return !y ? x : GCD(y,x%y);
		}
		void Update(int i,long long v)
		{
			long long l=s[i].l,r=s[i].r,size=r-l+1;
			s[i].lazy+=v;
			s[i].v[0]+=v*size;
			s[i].v[1]+=v*size*(l+r)>>1;
			s[i].v[2]+=v*(r*(r+1)*((r<<1)+1)-(l-1)*l*((l<<1)-1))/6LL;
		}
		void PushUp(int i)
		{
			for(int j=0;j<3;++j)
				s[i].v[j]=s[i<<1].v[j]+s[i<<1|1].v[j];
		}
		void PushDown(int i)
		{
			int j=i<<1;
			Update(j,s[i].lazy),Update(j+1,s[i].lazy);
			s[i].lazy=0;
		}
		long long Sum(int i,int l,int r,int k)
		{
			if(l==s[i].l && r==s[i].r)
				return s[i].v[k];
			if(s[i].l!=s[i].r && s[i].lazy)
				PushDown(i);
			int j=i<<1,mid=s[i].l+s[i].r>>1;
			if(r<=mid)
				return Sum(j,l,r,k);
			else if(l>mid)
				return Sum(j+1,l,r,k);
			else
				return Sum(j,l,mid,k)+Sum(j+1,mid+1,r,k);
		}
}T;
int main(int argc,char *argv[])
{
	scanf("%d %d",&n,&m);
	T.BuildTree(1,1,n-1);
	for(int i=1,l,r,v;i<=m;++i)
	{
		char c;
		scanf("\n%c %d %d",&c,&l,&r);
		if(c=='C')
		{
			scanf("%d",&v);
			T.Add(1,l,r-1,v);
		}
		else
			T.Ans(l,r);
	}
	return 0;
}

谢谢阅读。

posted @ 2018-02-22 20:37  Capella  阅读(140)  评论(2编辑  收藏  举报

谢谢光临