题意:有一个序列,一开始所有的元素都是ai,你可以选择两个长度相等的区间,如果某个元素被一个区间覆盖,那么变为bi,如果被两个区间都覆盖,那么变为ci。问所有区间的选择方法中产生的第k小的元素总和。

首先很容易想到的是二分答案,枚举一个区间,然后用线段树或树状数组查询另一个区间使得元素总和小于等于答案的数量。

为了方便计算,我们把b和c数组中的元素都减掉a,即bi=bi-ai,ci=ci-ai,这样只要查询两区间中元素之和小于等于答案的数量就行了,最后再把答案加上a中元素的和。

由于序列是静态的,因此可以对b和c求个前缀和。

当两区间不相交时,只要把右边的区间从左往右移动,并把左边的区间和动态加入树状数组中查询即可。

当两区间相交时,问题就比较复杂了。按照官方题解中的方法,需要引进两个辅助函数g和f,两者相加会产生"bcb"的效果,这样就又可以用树状数组统计了。

其中$g_x=\sum\limits _{i=1}^{x-1}{(c_i-2b_i)}+\sum\limits _{i=x}^{x+r-1}{(c_i-b_i)}$

$f_y=\sum\limits _{i=1}^{y-1}{(2b_i-c_i)}+\sum\limits _{i=y}^{y+r-1}{b_i}$

推导过程:

设$g_x=\sum\limits _{i=1}^{x-1}{g_1x}+\sum\limits _{i=x}^{x+r-1}{g_2x}$

$f_y=\sum\limits _{i=1}^{y-1}{f_1y}+\sum\limits _{i=y}^{y+r-1}{f_2y}$

则有:$\left\{\begin{matrix}\begin{aligned}&f_1+g_1=0\\&f_1+g_2=b\\&f_2+g_2=c\\&f_2=b\end{aligned}\end{matrix}\right.$

联立方程组即可求出$f_1,f_2,g_1,g_2$的值。

最后要注意的是,由于需要在树状数组上查询的值最多只有O(n)种,因此可以将要查询的值离散化。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=3e4+,inf=0x3f3f3f3f3f3f3f3fll;
ll n,len,k,a[N],b[N],c[N],C[N*],B[N*],n2,F[N],G[N],K[N],all;
ll lb(ll x) {return x&-x;}
void add(ll u,ll x) {for(; u<=n2; u+=lb(u))C[u]+=x;}
ll get(ll u) {ll ret=; for(; u; u-=lb(u))ret+=C[u]; return ret;}
ll sum(ll* t,ll l,ll r) {return t[r]-t[l-];}
ll g(ll x) {return sum(c,,x-)-*sum(b,,x-)+sum(c,x,x+len-)-sum(b,x,x+len-);}
ll f(ll x) {return *sum(b,,x-)-sum(c,,x-)+sum(b,x,x+len-);}
ll qry(ll x) {
ll cnt=;
for(ll i=; i<=n2; ++i)C[i]=;
for(ll i=len+; i+len-<=n; ++i) {
add(K[i-len]+,);
cnt+=get(upper_bound(B,B+n2,x-B[K[i]])-B);
}
for(ll i=; i<=n2; ++i)C[i]=;
for(ll i=; i+len-<=n; ++i) {
add(G[i-]+,);
if(i-len>=)add(G[i-len]+,-);
cnt+=get(upper_bound(B,B+n2,x-B[F[i]])-B);
}
return cnt;
}
ll bi(ll l,ll r) {
while(l<r) {
ll mid=l+((r-l)>>);
k<=qry(mid)?r=mid:l=mid+;
}
return l;
}
int main() {
scanf("%lld%lld%lld",&n,&len,&k);
for(ll i=; i<=n; ++i)scanf("%lld",&a[i]);
for(ll i=; i<=n; ++i)scanf("%lld",&b[i]);
for(ll i=; i<=n; ++i)scanf("%lld",&c[i]);
for(ll i=; i<=n; ++i)all+=a[i];
for(ll i=; i<=n; ++i)c[i]-=a[i],b[i]-=a[i];
for(ll i=; i<=n; ++i)b[i]+=b[i-],c[i]+=c[i-];
for(ll i=; i+len-<n; ++i)G[i]=g(i),B[n2++]=G[i];
for(ll i=; i+len-<=n; ++i)F[i]=f(i),B[n2++]=F[i];
for(ll i=; i+len-<=n; ++i)K[i]=sum(b,i,i+len-),B[n2++]=K[i];
B[n2++]=~inf,B[n2++]=inf;
sort(B,B+n2),n2=unique(B,B+n2)-B;
for(ll i=; i+len-<n; ++i)G[i]=lower_bound(B,B+n2,G[i])-B;
for(ll i=; i+len-<=n; ++i)F[i]=lower_bound(B,B+n2,F[i])-B;
for(ll i=; i+len-<=n; ++i)K[i]=lower_bound(B,B+n2,K[i])-B;
printf("%lld\n",all+bi(,c[n]));
return ;
}

Gym - 101630G The Great Wall (前缀和+树状数组+二分)的更多相关文章

  1. POJ 2828 Buy Tickets (线段树 or 树状数组+二分)

    题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容 ...

  2. TZOJ 4602 高桥和低桥(二分或树状数组+二分)

    描述 有个脑筋急转弯是这样的:有距离很近的一高一低两座桥,两次洪水之后高桥被淹了两次,低桥却只被淹了一次,为什么?答案是:因为低桥太低了,第一次洪水退去之后水位依然在低桥之上,所以不算“淹了两次”.举 ...

  3. POJ 2182 Lost Cows 【树状数组+二分】

    题目链接:http://poj.org/problem?id=2182 Lost Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submis ...

  4. 树状数组+二分||线段树 HDOJ 5493 Queue

    题目传送门 题意:已知每个人的独一无二的身高以及排在他前面或者后面比他高的人数,问身高字典序最小的排法 分析:首先对身高从矮到高排序,那么可以知道每个人有多少人的身高比他高,那么取较小值(k[i], ...

  5. P2161 [SHOI2009]会场预约[线段树/树状数组+二分/STL]

    题目描述 PP大厦有一间空的礼堂,可以为企业或者单位提供会议场地.这些会议中的大多数都需要连续几天的时间(个别的可能只需要一天),不过场地只有一个,所以不同的会议的时间申请不能够冲突.也就是说,前一个 ...

  6. The Stream of Corning 2( 权值线段树/(树状数组+二分) )

    题意: 有两种操作:1.在[l,r]上插入一条值为val的线段 2.问p位置上值第k小的线段的值(是否存在) 特别的,询问的时候l和p合起来是一个递增序列 1<=l,r<=1e9:1< ...

  7. 牛客多校第3场 J 思维+树状数组+二分

    牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...

  8. BZOJ-2743: [HEOI2012]采花 前缀和 树状数组

    BZOJ-2743 LUOGU:https://www.luogu.org/problemnew/show/P4113 题意: 给一个n长度的序列,m次询问区间,问区间中出现两次及以上的数字的个数.n ...

  9. [CSP-S模拟测试]:斯诺(snow)(数学+前缀和+树状数组)

    题目传送门(内部题37) 输入格式 第一行一个整数$n$,表示区间的长度. 第二行一个长度为$n$的只包含$0,1,2$的字符串,表示给出的序列. 输出格式 一行一个整数,表示革命的区间的数量. 样例 ...

随机推荐

  1. phpstorm 远程连接服务器进行开发

    phpstorm phpstorm是一款功能强大的ide编辑器,有了它,你敲代码速度能比用notepad++快数倍(初学者不建议使用ide,建议使用notepad++),缺点是没有固态的电脑带起来吃力 ...

  2. fiddler的使用:抓包定位、模拟弱网

    一.fiddler抓包定位 Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据(cookie,htm ...

  3. BeanFactory 和FactoryBean的区别

    转自:https://www.cnblogs.com/aspirant/p/9082858.html BeanFacotry是spring中比较原始的Factory.如XMLBeanFactory就是 ...

  4. Ubuntu下借助URLOS实现快速安装DzzOffice企业办公套件

    如今,越来越多的个人.团队甚至企业都在使用GSuite或者Office365等网络办公套件,为什么人们越来越喜爱使用网络办公套件?一方面是考虑数字资产的安全性以及管理效率,另一方面则是日益增大的协同办 ...

  5. java中连接数据库的步骤

    JDBC(连接数据库) 简单连接数据库的步骤: 1.将mysql的jdbc驱动加载到内存中 指定需要连接的数据库地址.用户名和密码: 2.获取连接: 3.通过连接创建Statement对象: 4.执行 ...

  6. 云风协程库coroutine源码分析

    前言 前段时间研读云风的coroutine库,为了加深印象,做个简单的笔记.不愧是大神,云风只用200行的C代码就实现了一个最简单的协程,代码风格精简,非常适合用来理解协程和用来提升编码能力. 协程简 ...

  7. RPC基本原理

    RPC非常重要,很多人面试的时候都挂在了这个地方!你要是还不懂RPC是什么?他的基本原理是什么?你一定要把下边的内容记起来!好好研究一下!特别是文中给出的一张关于RPC的基本流程图,重点中的重点,Du ...

  8. c++学习笔记之类和对象(一、类定义)

    类和对象是 C++ 的重要特性,它们使得 C++ 成为面向对象的编程语言. 类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量:创建对象的过程也叫类的实例化.每个对象都是类的一个 ...

  9. git使用技巧集合(持续更新中)

    git使用技巧集合(持续更新中) 在团队协作中,git.svn等工具是非常重要的,在此只记录一些git使用过程中遇到的问题以及解决方法,并且会持续更新. 1.git commit之后,还没push,如 ...

  10. Linux-2.1vim简单使用

    1.用vim打开文件,文件内容显示在终端,命令模式无法编辑 vim 1.txt vi 1.txt 2.使用a,i,o,shift+o编辑文件,按Esc退出编辑模式 i 插入在光标前 a 插入在光标后 ...