Codeforces 1136E - Nastya Hasn't Written a Legend - [线段树+二分]
题目链接:https://codeforces.com/problemset/problem/1136/E
题意:
给出一个 $a[1 \sim n]$,以及一个 $k[1 \sim (n-1)]$,初始保证所有的 $1 \le i \le n-1$ 都满足 $a[i]+k[i] \le a[i+1]$。
现在有两种操作:
第一种是令指定的 $a[i]$ 加上一个非负整数 $x$,此时若有 $a[i] + k[i] > a[i+1]$,则 $a[i+1]$ 变为 $a[i] + k[i]$,往后依次类推。
第二种是给定一个区间 $[l,r]$ 求 $a[l] + \cdots + a[r]$。
题解:
首先,我们知道对一个 $a[i]$ 加上 $x$ 后,根据其后面的 $a[i] + k[i] \le a[i+1], a[i+1] + k[i+1] \le a[i+2], \cdots$ 的“松紧程度”的变化,$a[i]$ 加上 $x$ 其带来的影响会逐步减弱,直到在某个位置 $j$ 之后完全消失,这个 $a[j]$ 是最后一个要被修改的数。
那么,如果我们找到了这个区间 $[i,j]$,我们现在要做的修改操作,就是要对这个区间进行一定的修改。
不难发现,这个区间内的第一个数变成了 $a[i]+x$,第二个变成了 $a[i]+x+k[i]$,第三个变成了 $a[i]+x+k[i]+k[i+1]$,依次类推……
考虑这个式子可以分为两部分:$a[i] + x$ 部分,以及 $k[i] + k[i+1] + \cdots$ 部分。
可以考虑分开维护这两个部分,前一部分很好维护,线段树区间更新;后一部分直接维护比较困难,我们可以这样维护:
$k[i],k[i]+k[i+1],k[i]+k[i+1]+k[i+2],\cdots$,不难看出是一个类似于 $k$ 数组的前缀和的求和,举个栗子:
$k_3 ,\: k_3+k_4 ,\: k_3+k_4+k_5 ,\: k_3+k_4+k_5+k_6$,如果是前缀和求和,那么应当是 $k_1+k_2+k_3 \:,\: k_1+k_2+k_3+k_4 \:,\: k_1+k_2+k_3+k_4+k_5 \:,\: k_1+k_2+k_3+k_4+k_5+k_6$。
也就是说,要在前缀和上减掉 $4 \times (k_1+k_2)$,不难发现,这个值是比较好维护的,是对某一段区间直接赋值,所以可以用线段树维护这个东西。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int maxn=1e5+;
int n,q;
ll a[maxn],k[maxn],s[maxn]; struct Node
{
int l,r;
ll val,lazy;
void update(ll x)
{
val=(r-l+)*x;
lazy=x;
}
};
struct SegmentTree
{
#define ls (rt<<1)
#define rs (rt<<1|1)
Node o[maxn<<];
void pushdown(int rt)
{
if(o[rt].lazy!=-INF)
{
o[ls].update(o[rt].lazy);
o[rs].update(o[rt].lazy);
o[rt].lazy=-INF;
}
}
void pushup(int rt)
{
o[rt].val=o[ls].val+o[rs].val;
}
void build(int rt,int l,int r,ll v[])
{
o[rt].l=l, o[rt].r=r;
o[rt].lazy=-INF;
if(l==r)
{
o[rt].val=v[l];
return;
}
int mid=(l+r)>>;
build(ls,l,mid,v);
build(rs,mid+,r,v);
pushup(rt);
}
void update(int rt,int st,int ed,ll val)
{
if(st<=o[rt].l && o[rt].r<=ed)
{
o[rt].update(val);
return;
}
pushdown(rt);
int mid=(o[rt].l+o[rt].r)>>;
if(st<=mid) update(ls,st,ed,val);
if(mid<ed) update(rs,st,ed,val);
pushup(rt);
}
ll query(int rt,int st,int ed)
{
if(st<=o[rt].l && o[rt].r<=ed) return o[rt].val;
pushdown(rt);
ll res=;
int mid=(o[rt].l+o[rt].r)>>;
if(st<=mid) res+=query(ls,st,ed);
if(mid<ed) res+=query(rs,st,ed);
return res;
}
}T[]; inline ll getval(int p)
{
return T[].query(,p,p)+k[p]-T[].query(,p,p);
}
void modify(int p,ll x)
{
int l=p, r=n;
ll base=getval(p);
while(l<r)
{
int mid=(l+r+)>>;
if(base+x+k[mid]-k[p]>getval(mid)) l=mid;
else r=mid-;
}
T[].update(,p,r,base+x);
T[].update(,p,r,k[p]);
} int main()
{
ios::sync_with_stdio();
cin.tie(), cout.tie(); cin>>n;
for(int i=;i<=n;i++) cin>>a[i]; k[]=s[]=;
for(int i=;i<=n;i++) cin>>k[i], k[i]+=k[i-], s[i]=s[i-]+k[i]; T[].build(,,n,a);
T[].build(,,n,k); cin>>q;
char op[];
while(q--)
{
cin>>op;
if(op[]=='+')
{
int p; ll x; cin>>p>>x;
modify(p,x);
}
if(op[]=='s')
{
int l,r; cin>>l>>r;
ll res1=T[].query(,l,r);
ll res2=s[r]-s[l-]-T[].query(,l,r);
cout<<res1+res2<<'\n';
}
}
}
有一个注意点是懒标记初始化成负无穷。
Codeforces 1136E - Nastya Hasn't Written a Legend - [线段树+二分]的更多相关文章
- Codeforces 1136E Nastya Hasn't Written a Legend 线段树
vp的时候没码出来.. 我们用set去维护, 每一块区域, 每块区域内的元素与下一个元素的差值刚好为ki,每次加值的时候我们暴力合并, 可以发现我们最多合并O(n)次. 然后写个线段树就没了. #in ...
- Codeforces 1136E Nastya Hasn't Written a Legend (线段树教做人系列)
题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后, ...
- codeforces#1136E. Nastya Hasn't Written a Legend(二分+线段树)
题目链接: http://codeforces.com/contest/1136/problem/E 题意: 初始有a数组和k数组 有两种操作,一,求l到r的区间和,二,$a_i\pm x$ 并且会有 ...
- Codeforces Gym 100803G Flipping Parentheses 线段树+二分
Flipping Parentheses 题目连接: http://codeforces.com/gym/100803/attachments Description A string consist ...
- Codeforces Gym 100231B Intervals 线段树+二分+贪心
Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...
- [Codeforces 464E] The Classic Problem(可持久化线段树)
[Codeforces 464E] The Classic Problem(可持久化线段树) 题面 给出一个带权无向图,每条边的边权是\(2^{x_i}(x_i<10^5)\),求s到t的最短路 ...
- Educational Codeforces Round 64 (Rated for Div. 2) (线段树二分)
题目:http://codeforces.com/contest/1156/problem/E 题意:给你1-n n个数,然后求有多少个区间[l,r] 满足 a[l]+a[r]=max([l, ...
- Codeforces 671C - Ultimate Weirdness of an Array(线段树维护+找性质)
Codeforces 题目传送门 & 洛谷题目传送门 *2800 的 DS,不过还是被我自己想出来了 u1s1 这个 D1C 比某些 D1D 不知道难到什么地方去了 首先碰到这类问题我们肯定考 ...
- Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq
B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/pro ...
随机推荐
- 数据分析:基于Python的自定义文件格式转换系统
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- np.memmap读取大文件
Numpy中的ndarray是一种新形式的Python内建类型.因此,它可以在需要时被继承.ndarray形成了许多有用类的基础. np.memmap就是其中一种,它是内存映射文件.本质上就是使用C语 ...
- linux驱动(续)
网络通信 --> IO多路复用之select.poll.epoll详解 IO多路复用之select.poll.epoll详解 目前支持I/O多路复用的系统调用有 select,psel ...
- CentOS 6.5 x64下网络配置
一.自动获取IP地址 #dhclient 自动获取ip地址命令 #ifconfig 查询系统里网卡信息,ip地址.MAC地址 [root@CentOS6 ~]# vi /etc/sysconfig/n ...
- repo命令详解
Android 为企业提供一个新的市场,无论大企业,小企业都是处于同一个起跑线上.研究 Android 尤其是 Android 系统核心或者是驱动的开发,首先需要做的就是本地克隆建立一套 Androi ...
- HTML中 javascript 相对根路径问题
在HTML文档中,有很多引用的JS或者CSS文件,一般都是用相对路径来引用的,例如: ./../.. ,但是,有没有类似ASP.NET中的路径: ~/Scripts/myScript.js 但是有的: ...
- Airtest iOS测试环境部署
[本文出自天外归云的博客园] 简介 这个Airtest IDE是通过iOS-Tagent来操作iPhone的,你可以在Airtest IDE里录制脚本来实现自动化操作iPhone 前提 1. 得有个i ...
- C语言 · 单词数统计
单词数统计 输入一个字符串,求它包含多少个单词. 单词间以一个或者多个空格分开. 第一个单词前,最后一个单词后也可能有0到多个空格. 比如:" abc xyz" 包含两个单词 ...
- 全局Threshold和动态阈值分割Dyn_Threshold的应用场景
手册里面的particle例子,例子的任务是分析颗粒在液体中.在这个应用程序的主要困难:存在两种类型的对象:大明亮物体和较低的小物体的对比.此外噪音使分割的存在困难:无法使用全局灰度阈值thresho ...
- Oracle分析函数-first_value()和last_value()
first_value()和last_value()字面意思已经很直观了,取首尾记录值.例:查询部门最早发生销售记录日期和最近发生的销售记录日期 select dept_id ,sale_date , ...