HAOI2012高速公路bzoj2752 (线段树,数学)

题目大意:
给定一个长度为n的链,一共m次操作
对于每次操作
\(C\ l\ r\ x\)表示将第l个点到第r个点之间的所有道路的权值增加v

\(Q\ l\ r\)在第l个到第r个点里等概率随机取出两个不同的点a和b,那么从a行驶到b将期望花费多少费用呢

QwQ我们可以考虑将期望分为分子和分母两部分

首先考虑分母,分母就是在\(r-l+1\)个点中选两个点的方案数,也就是\({r-l+1}\choose 2\)

而分子就是总权值了

对于一个在\([l,r]\)的点\(i\)来说
它会被计算\((i-l+1)\times (r-i+1)\)次 (就跟分别在左右两个区间枚举端点是一样的)

那么我们求的东西也就变成了

\(\sum_{i=l}^{r} w[i]\times(i-l+1)\times(r-i+1)\)

我们考虑将它展开:
\(\sum_{i=l}^{r} w[i]\times((r+l)\times i-i\times i +(r-l+1-r\times l))\)

再进一步来一波,对于区间\([l,r]\)我们就是求的是:
\((r+l)\times \sum_{i=l}^{r}w[i]\times i + (r-l+1-r\times l)\times \sum_{i=l}^{r}w[i] + \sum_{i=l}^{r}w[i]*i^2\)

而对于更新,我们也不难找出一些规律了咯

所以对于一个区间,我们只需要维护一个\(w[i],w[i]*i,w[i]*i^2,i^2,i\)的sigma值就能处理更新和合并了!

void up(int root)
{
	f[root].si=f[2*root].si+f[2*root+1].si;
	f[root].sii=f[2*root].sii+f[2*root+1].sii;
	f[root].scostii=f[2*root].scostii+f[2*root+1].scostii;
	f[root].scosti=f[2*root].scosti+f[2*root+1].scosti;
	f[root].scost=f[2*root].scost+f[2*root+1].scost;
}

void pushdown(int root,int l,int r)
{
   ll mid = (l+r) >> 1;
   if (add[root])
   {
   	  add[2*root]+=add[root];
   	  add[2*root+1]+=add[root];
   	  f[2*root].scost+=add[root]*(mid-l+1);
   	  f[2*root+1].scost+=add[root]*(r-mid);
   	  f[2*root].scosti+=add[root]*f[2*root].si;
   	  f[2*root+1].scosti+=add[root]*f[2*root+1].si;
   	  f[2*root].scostii+=add[root]*f[2*root].sii;
   	  f[2*root+1].scostii+=add[root]*f[2*root+1].sii;
   	  add[root]=0;
   }
}

emmmmm
query的时候也记得\(\times\)的时候要乘询问的总区间,而不是当然区间!

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<map>
#include<vector>
#define ll long long
using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int maxn = 1e5+1e2;

struct Node{
   ll scost,scosti,scostii,si,sii;
   ll ans;
};

Node f[4*maxn];
ll add[4*maxn];
int n,m;

ll count(int xx,int yy)
{
	ll x=xx,y=yy;
	return (y-x+1)*(y-x+2)/2;
}

void up(int root)
{
	f[root].si=f[2*root].si+f[2*root+1].si;
	f[root].sii=f[2*root].sii+f[2*root+1].sii;
	f[root].scostii=f[2*root].scostii+f[2*root+1].scostii;
	f[root].scosti=f[2*root].scosti+f[2*root+1].scosti;
	f[root].scost=f[2*root].scost+f[2*root+1].scost;
}

void pushdown(int root,int l,int r)
{
   ll mid = (l+r) >> 1;
   if (add[root])
   {
   	  add[2*root]+=add[root];
   	  add[2*root+1]+=add[root];
   	  f[2*root].scost+=add[root]*(mid-l+1);
   	  f[2*root+1].scost+=add[root]*(r-mid);
   	  f[2*root].scosti+=add[root]*f[2*root].si;
   	  f[2*root+1].scosti+=add[root]*f[2*root+1].si;
   	  f[2*root].scostii+=add[root]*f[2*root].sii;
   	  f[2*root+1].scostii+=add[root]*f[2*root+1].sii;
   	  add[root]=0;
   }
}

void build(int root,int l,int r)
{
	if (l==r)
	{
		f[root].si=(long long)1LL*l;
		f[root].sii=(long long) 1LL*l*l;
		return;
	}
	int mid = (l+r) >> 1;
    build(2*root,l,mid);
    build(2*root+1,mid+1,r);
    up(root);
}

void update(int root,int l,int r,int x,int y,ll p)
{
	if (x<=l && r<=y)
	{
	    ll len=r-l+1;
		f[root].scost+=1LL*p*len;
		f[root].scosti+=1LL*p*f[root].si;
		f[root].scostii+=1LL*p*f[root].sii;
		add[root]+=p;
		return;
	}
	pushdown(root,l,r);
	int mid = (l+r) >> 1;
	if (x<=mid) update(2*root,l,mid,x,y,p);
	if (y>mid) update(2*root+1,mid+1,r,x,y,p);
	up(root);
}

ll query(int root,int l,int r,int x,int y)
{
	if (x<=l && r<=y)
	{
		ll xx = x,yy=y;
		return (long long)1LL*(xx+yy)*f[root].scosti+(long long)1LL*(yy-xx+1-xx*yy)*f[root].scost-f[root].scostii;
	}
	pushdown(root,l,r);
	int mid = (l+r) >> 1;
	ll ans=0;
	if (x<=mid) ans+=query(2*root,l,mid,x,y);
	if (y>mid) ans+=query(2*root+1,mid+1,r,x,y);
	return ans;
}

int main()
{
  scanf("%d%d",&n,&m);
  n--;
  build(1,1,n); 
  for (int i=1;i<=m;i++)
  {
  	 char s[10];
  	 scanf("%s",s+1);
  	 if (s[1]=='C')
  	 {
  	 	int x,y;
	    ll z;
  	 	scanf("%d%d%lld",&x,&y,&z);
		y--;
  	 	update(1,1,n,x,y,z);
	   }
	 if (s[1]=='Q')
	 {
	    int x,y;
	    scanf("%d%d",&x,&y);
	    y--;
	    ll tmp=query(1,1,n,x,y);
	    ll tmp1=count(x,y);
	    printf("%lld/%lld\n",tmp/__gcd(tmp1,tmp),tmp1/__gcd(tmp1,tmp));
	 }
  }
  return 0;
}

posted @ 2018-12-22 12:59  y_immortal  阅读(108)  评论(0编辑  收藏  举报