[HAOI2012]高速公路

题目描述

Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。

Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。

政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。

无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l<r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?

输入输出格式

输入格式:

第一行2个正整数N,M,表示有N个收费站,M次调整或询问

接下来M行,每行将出现以下两种形式中的一种

C l r v 表示将第l个收费站到第r个收费站之间的所有道路的通行费全部增加v

Q l r 表示对于给定的l,r,要求回答小A的问题

所有C与Q操作中保证1<=l<r<=N

输出格式:

对于每次询问操作回答一行,输出一个既约分数

若答案为整数a,输出a/1

输入输出样例

输入样例#1:
4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4
输出样例#1:
1/1
8/3
17/6

说明

所有C操作中的v的绝对值不超过10000

在任何时刻任意道路的费用均为不超过10000的非负整数

所有测试点的详细情况如下表所示



数学期望+线段树+GCD(就约分用了)
首先我们考虑在l到r之间的期望(第i到i+1为第i段,所以线段树长度为n-1)
Σp val[p]*(r-i)*(i-l+1)/(r-l+1)*(r-l)
我们来分析一下:
分母部分为r-l+1个路段中选两个端点的方案种数
分子部分考虑每一个位置p对期望的贡献可以得到
接着要动态修改val值并查询答案
把上式拆开:
Σval[p]*(r-l*r)+val[p]*p*(l+r-1)-val[p]*p*p
用一种支持区间修改查询的数据结构:线段树。来维护3种信息:区间signma(val[p]),signma(val[p]*p),signma(val[p]*p*p)
signma(val[p])的维护:直接在和上+(r-l+1)*add
signma(val[p]*p)的维护:利用等差数列公式,+(r-l+1)*(l+r)/2*add
signma(val[p]*p*p)的维护:利用平方和公式:12+22+.....+n2=(2*n+1)*(n+1)*n/6
注意long long小心整形溢出
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 typedef long long lol;
  7 struct Node
  8 {
  9     lol s[5];
 10     lol lazy;
 11     lol l,r;
 12 }c[400001];
 13 lol n,m;
 14 lol ans[5];
 15 //2signma(vp(L-LR)+vp*p(L+R-1)-vp*p*p)/(R-L+1)(R-L) 
 16 char get_op()
 17 {
 18     char ch=getchar();
 19     while (ch!='C'&&ch!='Q') ch=getchar();
 20     return ch;
 21 }
 22 lol gcd(lol x,lol y)
 23 {
 24     if (!y) return x;
 25     return gcd(y,x%y);
 26 } 
 27 lol get(lol r,lol l)
 28 {
 29     return ((2*r+1)*(r+1)*r/6-(2*l-1)*(l-1)*l/6);
 30 }
 31 void change(int rt,lol v)
 32 {
 33     c[rt].s[1]+=v*(c[rt].r-c[rt].l+1);
 34     c[rt].s[2]+=(c[rt].l+c[rt].r)*(c[rt].r-c[rt].l+1)/2*v;
 35     c[rt].s[3]+=v*(get(c[rt].r,c[rt].l));
 36     c[rt].lazy+=v;    
 37 }
 38 void pushup(int rt)
 39 {
 40     int i;
 41     for (i=1;i<=3;i++)
 42     {
 43         c[rt].s[i]=c[rt*2].s[i]+c[rt*2+1].s[i];
 44     }
 45 }
 46 void pushdown(int rt)
 47 {
 48     if (c[rt].lazy)
 49     {
 50         change(rt*2,c[rt].lazy);
 51         change(rt*2+1,c[rt].lazy);
 52         c[rt].lazy=0;
 53     }
 54 }
 55 void update(int rt,lol l,lol r,lol L,lol R,lol d)
 56 {
 57     if (l>=L&&r<=R)
 58     {
 59         change(rt,d);
 60         return;
 61     }
 62     lol mid=(l+r)/2;
 63     pushdown(rt);
 64     if (L<=mid) update(rt*2,l,mid,L,R,d);
 65     if (R>mid) update(rt*2+1,mid+1,r,L,R,d);
 66     pushup(rt);
 67 }
 68 lol query(int rt,lol l,lol r,lol L,lol R,int k)
 69 {
 70     if (l>=L&&r<=R)
 71     {
 72         return c[rt].s[k]; 
 73     }
 74     lol mid=(l+r)/2,ss=0;
 75     pushdown(rt);
 76     if (L<=mid) ss+=query(rt*2,l,mid,L,R,k);
 77     if (R>mid) ss+=query(rt*2+1,mid+1,r,L,R,k);
 78  pushup(rt);
 79  return ss;
 80 }
 81 void build(int rt,lol l,lol r)
 82 {
 83    c[rt].l=l;c[rt].r=r;
 84     if (l==r) return;
 85      lol mid=(l+r)/2;
 86      build(rt*2,l,mid);
 87       build(rt*2+1,mid+1,r);
 88 }
 89 int main()
 90 {lol i,l,r,j;
 91 lol p,d;
 92  char opt;
 93     cin>>n>>m;
 94     build(1,1,n-1);
 95      for (i=1;i<=m;i++)
 96      {
 97          opt=get_op();
 98          if (opt=='C') 
 99          {
100              scanf("%lld%lld%lld",&l,&r,&d);
101              update(1,1,n-1,l,r-1,d);
102         }
103         else 
104         {
105             scanf("%lld%lld",&l,&r);
106             p=(r-l+1)*(r-l)/2;
107             for (j=1;j<=3;j++)
108              ans[j]=query(1,1,n-1,l,r-1,j);
109              //cout<<ans[1]<<' '<<ans[2]<<' '<<ans[3]<<endl;
110              ans[0]=(r-l*r)*ans[1]+(l+r-1)*ans[2]-ans[3];
111              //cout<<ans[0]<<' '<<p<<endl;
112              lol g=gcd(ans[0],p);
113              printf("%lld/%lld
",ans[0]/g,p/g);
114         }
115      }
116 }
 
原文地址:https://www.cnblogs.com/Y-E-T-I/p/7234968.html