[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;
}

谢谢阅读。

[Luogu 2221] HAOI2012 高速公路的更多相关文章

  1. 【题解】Luogu P2221 [HAOI2012]高速公路

    原题传送门 这道题还算简单 我们要求的期望值: \[\frac{\sum_{i=l}^r\sum_{j=l}^rdis[i][j]}{C_{r-l+1}^{2}}\] 当然是上下两部分分别求,下面肥肠 ...

  2. luogu P2221 [HAOI2012]高速公路题解

    题面 很套路的拆式子然后线段树上维护区间和的题.一般都是把式子拆成区间内几个形如\(\sum i*a_i, \sum i^2 * a_i\)的式子相加减的形式. 考虑一次询问[l,r]的答案怎么算: ...

  3. BZOJ2752: [HAOI2012]高速公路(road)

    2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 608  Solved: 199[Submit][ ...

  4. BZOJ 2752: [HAOI2012]高速公路(road)( 线段树 )

    对于询问[L, R], 我们直接考虑每个p(L≤p≤R)的贡献,可以得到 然后化简一下得到 这样就可以很方便地用线段树, 维护一个p, p*vp, p*(p+1)*vp就可以了 ----------- ...

  5. 【线段树】BZOJ2752: [HAOI2012]高速公路(road)

    2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1621  Solved: 627[Submit] ...

  6. BZOJ 2752: [HAOI2012]高速公路(road) [线段树 期望]

    2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1219  Solved: 446[Submit] ...

  7. P2221 [HAOI2012]高速公路(线段树)

    P2221 [HAOI2012]高速公路 显然答案为 $\dfrac{\sum_{i=l}^r\sum_{j=l}^{r}dis[i][j]}{C_{r-l+1}^2}$ 下面倒是挺好算,组合数瞎搞 ...

  8. BZOJ 2752:[HAOI2012]高速公路(road)(线段树)

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

  9. 【BZOJ2752】【Luogu P2221】 [HAOI2012]高速公路

    不是很难的一个题目.正确思路是统计每一条边被经过的次数,但我最初由于习惯直接先上了一个前缀和再推的式子,导致极其麻烦难以写对而且会爆\(longlong\). 推导过程请看这里. #include & ...

随机推荐

  1. 图的遍历——BFS(队列实现)

    #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> ...

  2. windows编程了解

    文章:浅谈Windows API编程 (这个经典)

  3. ServletContext域对象

    场景:假设某个web服务,有两个servlet分别是servlet1和servlet2,servlet1要传参数name=zhangsan传送给servlet2,传统方法如下: servlet1端:用 ...

  4. java---迭代器(Iterator)

    迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭代器通常被称为“轻量级”对象,因为创建它的代价小. Java中的Iterator功能比较简单, ...

  5. Swift-函数的理解

    /* 函数(Function) 函数是为执行特定功能的自包含的代码块.函数需要给定一个特定标识符(名字),然后当需要的时候, 就调用此函数来执行功能. */ // 函数的定义与调用 // 定义函数时, ...

  6. css那些事儿4 背景图像

    background:背景颜色,图像,平铺方式,大小,位置 能够显示背景区域即为盒子模型的填充和内容部分,其中背景图像将会覆盖背景颜色.常见的水平或垂直渐变颜色背景通常使用水平或垂直渐变的背景图像在水 ...

  7. ZigBee设备入网流程之关联方式

    ZigBee设备入网流程 ZigBee设备入网有关联方式和直接方式两种,我所熟悉的是关联方式,这也是最常用的方式. 关联方式 step1 设备发出Beacon Request 设备会在预先设置的几个信 ...

  8. VUE01指令

    一.下载Vue2.0的两个版本: 官方网站:http://vuejs.org/ 开发版本:包含完整的警告和调试模式 生产版本:删除了警告,进行了压缩 二.项目结构搭建 这个部分要视频中有详细讲解. 三 ...

  9. [OS] 多线程--第一次亲密接触CreateThread与_beginthreadex本质区别

    转自:http://blog.csdn.net/morewindows/article/details/7421759 本文将带领你与多线程作第一次亲密接触,并深入分析CreateThread与_be ...

  10. 【Python】python更新数据库脚本两种方法

    最近项目的两次版本迭代中,根据业务需求的变化,需要对数据库进行更新,两次分别使用了不同的方式进行更新. 第一种:使用python的MySQLdb模块利用原生的sql语句进行更新   1 import ...