BZOJ 2752 [HAOI2012]高速公路(road):线段树【维护区间内子串和】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2752
题意:
有一个初始全为0的,长度为n的序列a。
有两种操作:
(1)C l r v: 将[l,r)内的数全部加v。
(2)Q l r: 在[l,r)内随机选两个数x,y(x < y),问你∑(a[x to y])的期望,用最简分数形式输出。
题解:
首先,题中要求的期望 = 区间内所有子串之和 / 区间内子串个数。
如果一个区间的长度为len,显然区间内的子串个数为len*(len+1)/2。
所以题目就变成了怎样维护区间内所有子串之和。
dat表示某个区间的子串和。
假设有两个相邻区间l,r,合并起来的区间叫x。
那么dat[x] = dat[x] + dat[y] + 跨两个区间的子串和
所以接下来考虑如何求跨区间的子串和。
sum表示某个区间的所有元素之和。
ln表示区间l的长度,rn表示区间r的长度。
ls表示某个区间的所有所有前缀之和,rs表示某个区间的所有后缀之和。
则跨区间的子串之和 = rs[l]*rn + ls[r]*ln
即dat[x] = dat[x] + dat[y] + rs[l]*rn + ls[r]*ln
ls,rs和sum的合并就很好求了:
ls[x] = ls[l] + rn*sum[l] + ls[r]
rs[x] = rs[r] + ln*sum[r] + rs[l]
sum[x] = sum[l] + sum[r]
这样线段树的pushup函数就写完了。
然后考虑如何pushdown传标记。
tag表示某个区间被同时加了多少。
现在只考虑当前节点x的某一个儿子y,儿子y的区间长度为len。
首先考虑tag[x]对dat[y]的贡献。
贡献 = 枚举子串的长度 * 这种长度的子串个数 * tag[x]
即:dat[y] += ∑ i*(len-i+1)*tag[x],其中i∈[1,len]。
化简得:dat[y] += ( len*(len+1)/2*(len+1) + ∑(i^2) ) * tag[x]
对于其中的∑(i^2),事先O(n)预处理出来一个平方前缀和数组sqr即可。
然后易得tag[x]对ls,rs,sum的贡献:
ls[y] += len*(len+1)/2*tag[x]
rs[y] += len*(len+1)/2*tag[x]
sum[y] += len*tag[x]
这样pushdown也就写好了。
然后大力线段树即可QAQ……
AC Code:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAX_N 100005
#define MAX_T 400005
#define int ll using namespace std; typedef long long ll; struct Node
{
int dt,ls,rs,s,ln;
Node(int _dt,int _ls,int _rs,int _s,int _ln)
{
dt=_dt; ls=_ls; rs=_rs; s=_s; ln=_ln;
}
Node(){}
friend Node mix(const Node &a,const Node &b)
{
int _dt=a.dt+b.dt+a.rs*b.ln+b.ls*a.ln;
int _ls=a.ls+b.ln*a.s+b.ls;
int _rs=b.rs+a.ln*b.s+a.rs;
int _s=a.s+b.s;
int _ln=a.ln+b.ln;
return Node(_dt,_ls,_rs,_s,_ln);
}
}; int n,m;
int ls[MAX_T];
int rs[MAX_T];
int dat[MAX_T];
int sum[MAX_T];
int tag[MAX_T];
int sqr[MAX_N]; void cal_sqr()
{
for(int i=;i<=n;i++) sqr[i]=sqr[i-]+i*i;
} void push_up(int x,int len)
{
int l=x*+,r=x*+;
Node L(dat[l],ls[l],rs[l],sum[l],len-(len>>));
Node R(dat[r],ls[r],rs[r],sum[r],(len>>));
Node tmp=mix(L,R);
dat[x]=tmp.dt;
ls[x]=tmp.ls;
rs[x]=tmp.rs;
sum[x]=tmp.s;
} void push_down(int x,int len)
{
if(tag[x])
{
int l=x*+,r=x*+;
int ln=(len-(len>>)),rn=(len>>);
dat[l]+=(ln*(ln+)/*(ln+)-sqr[ln])*tag[x];
dat[r]+=(rn*(rn+)/*(rn+)-sqr[rn])*tag[x];
ls[l]+=ln*(ln+)/*tag[x];
ls[r]+=rn*(rn+)/*tag[x];
rs[l]+=ln*(ln+)/*tag[x];
rs[r]+=rn*(rn+)/*tag[x];
sum[l]+=ln*tag[x];
sum[r]+=rn*tag[x];
tag[l]+=tag[x];
tag[r]+=tag[x];
tag[x]=;
}
} void update(int a,int b,int k,int l,int r,int x)
{
if(a<=l && r<=b)
{
int len=r-l+;
tag[k]+=x;
sum[k]+=len*x;
ls[k]+=len*(len+)/*x;
rs[k]+=len*(len+)/*x;
dat[k]+=(len*(len+)/*(len+)-sqr[len])*x;
return;
}
if(r<a || b<l) return;
push_down(k,r-l+);
int mid=(l+r)>>;
update(a,b,k*+,l,mid,x);
update(a,b,k*+,mid+,r,x);
push_up(k,r-l+);
} Node query(int a,int b,int k,int l,int r)
{
if(a<=l && r<=b) return Node(dat[k],ls[k],rs[k],sum[k],r-l+);
if(r<a || b<l) return Node(,,,,);
push_down(k,r-l+);
int mid=(l+r)>>;
Node v1=query(a,b,k*+,l,mid);
Node v2=query(a,b,k*+,mid+,r);
return mix(v1,v2);
} signed main()
{
scanf("%lld%lld",&n,&m);
n--;
cal_sqr();
char opt[];
int l,r,v;
while(m--)
{
scanf("%s%lld%lld",opt,&l,&r);
if(opt[]=='C')
{
scanf("%lld",&v);
update(l,r-,,,n,v);
}
else
{
int dt=query(l,r-,,,n).dt;
int len=r-l;
int tot=len*(len+)/;
int g=__gcd(dt,tot);
printf("%lld/%lld\n",dt/g,tot/g);
}
}
}
BZOJ 2752 [HAOI2012]高速公路(road):线段树【维护区间内子串和】的更多相关文章
- BZOJ 2752: [HAOI2012]高速公路(road)( 线段树 )
对于询问[L, R], 我们直接考虑每个p(L≤p≤R)的贡献,可以得到 然后化简一下得到 这样就可以很方便地用线段树, 维护一个p, p*vp, p*(p+1)*vp就可以了 ----------- ...
- BZOJ 2752: [HAOI2012]高速公路(road) [线段树 期望]
2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1219 Solved: 446[Submit] ...
- bzoj 2752: [HAOI2012]高速公路(road)
Description Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站.Y901高速公路是一条由N-1段路以及N个收 ...
- ●BZOJ 2752 [HAOI2012]高速公路(road)
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2752题解: 期望,线段树. 把每个路段看成一个点,那么对于l~R的操作,就可以转化为对l~r ...
- BZOJ2752: [HAOI2012]高速公路(road)(线段树 期望)
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1820 Solved: 736[Submit][Status][Discuss] Descripti ...
- 【bzoj2752】[HAOI2012]高速公路(road) 线段树
题目描述 Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站.Y901高速公路是一条由N-1段路以及N个收费站组成的东西 ...
- 【GDKOI2016Day1T1-魔卡少女】【拆位】线段树维护区间内所有连续子区间的异或和
题意:给出N个数,M个操作.操作有修改和询问两种,每次修改将一个数改成另一个数,每次询问一个区间的所有连续子区间的异或和.n,m<=100000,ai<=1000 题解: 当年(其实也就是 ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- Can you answer these queries V SPOJ - GSS5 (分类讨论+线段树维护区间最大子段和)
recursion有一个整数序列a[n].现在recursion有m次询问,每次她想知道Max { A[i]+A[i+1]+...+A[j] ; x1 <= i <= y1 , x2 &l ...
随机推荐
- CSS3边框border-radius
一.官方解释 设置或检索对象使用圆角边框.提供2个参数,2个参数以“/”分隔,每个参数允许设置1~4个参数值,第1个参数表示水平半径,第2个参数表示垂直半径,如第2个参数省略,则默认等于第1个参数. ...
- Java源码之Object
本文出自:http://blog.csdn.net/dt235201314/article/details/78318399 一丶概述 JAVA中所有的类都继承自Object类,就从Object作为源 ...
- camke GUI工具 选择 vs2017 时,如何指定工具集 v140 而不是默认的 v141?
在参数位置加入 v140 即可,不需要加 -T
- CentOS 7.4 防火墙&网卡设置
防火墙 查看防火墙状态 临时关闭防火墙 (关闭的是当前正在运行的防火墙,重启时还是会自启) 彻底关闭防火墙 (开机不会再自启) 开启防火墙 查看防火墙状态 网卡 查看网卡状态
- 我的Android进阶之旅------>Android 众多的布局属性详解
Android功能强大,界面华丽,但是众多的布局属性就害苦了开发者,下面这篇文章结合了网上不少资料,希望对读者有用. 第一类:属性值为true或false android:layout_centerH ...
- linux安装jdk_1.8
转载自http://blog.csdn.net/ldl22847/article/details/7605650 1.下载jdk的rpm安装包,这里以jdk-8u141-linux-x64.rpm为例 ...
- 二值法方法综述及matlab程序
在某些图像处理当中一个关键步是二值法,二值化一方面能够去除冗余信息,另一方面也会使有效信息丢失.所以有效的二值化算法是后续的处理的基础.比如对于想要最大限度的保留下面图的中文字,以便后续的定位处理. ...
- iOS Application Project与OS X Application Project对于plist使用的区别
前几天因为在开源中国看到一个求源代码的问题: 模拟一个动物园系统MyZoo 1.动物园里面有三种动物:Panda,Elephant,Kangaroo 2.三种动物都有一定的数量(不止一只) 3.动物有 ...
- LeetCode:整数转罗马数字【12】
LeetCode:整数转罗马数字[12] 题目描述 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 10 ...
- HTML+CSS理解
HTML+CSS1.对WEB标准以及W3C的理解与认识标签闭合.标签小写.不乱嵌套.提高搜索机器人搜索几率.使用外 链css和js脚本.结构行为表现的分离.文件下载与页面速度更快.内容能被更多的用户所 ...