题目链接: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 - [线段树+二分]的更多相关文章

  1. Codeforces 1136E Nastya Hasn't Written a Legend 线段树

    vp的时候没码出来.. 我们用set去维护, 每一块区域, 每块区域内的元素与下一个元素的差值刚好为ki,每次加值的时候我们暴力合并, 可以发现我们最多合并O(n)次. 然后写个线段树就没了. #in ...

  2. Codeforces 1136E Nastya Hasn't Written a Legend (线段树教做人系列)

    题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后, ...

  3. codeforces#1136E. Nastya Hasn't Written a Legend(二分+线段树)

    题目链接: http://codeforces.com/contest/1136/problem/E 题意: 初始有a数组和k数组 有两种操作,一,求l到r的区间和,二,$a_i\pm x$ 并且会有 ...

  4. Codeforces Gym 100803G Flipping Parentheses 线段树+二分

    Flipping Parentheses 题目连接: http://codeforces.com/gym/100803/attachments Description A string consist ...

  5. Codeforces Gym 100231B Intervals 线段树+二分+贪心

    Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...

  6. [Codeforces 464E] The Classic Problem(可持久化线段树)

    [Codeforces 464E] The Classic Problem(可持久化线段树) 题面 给出一个带权无向图,每条边的边权是\(2^{x_i}(x_i<10^5)\),求s到t的最短路 ...

  7. 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, ...

  8. Codeforces 671C - Ultimate Weirdness of an Array(线段树维护+找性质)

    Codeforces 题目传送门 & 洛谷题目传送门 *2800 的 DS,不过还是被我自己想出来了 u1s1 这个 D1C 比某些 D1D 不知道难到什么地方去了 首先碰到这类问题我们肯定考 ...

  9. 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 ...

随机推荐

  1. NOIP2011普及组 数字反转

    题目OJ链接: http://codevs.cn/problem/1130/ https://www.luogu.org/problemnew/show/P1307 2011年NOIP全国联赛普及组 ...

  2. window炫丽cmd的别名cmder

    windows下的cmd,色彩度用起来不爽,cmder是对cmd的补充,界面很清爽 01.下载 https://github.com/cmderdev/cmder http://cmder.net/ ...

  3. Spark 官方博文专区(目录)

    关于转载一些 Spark 官方的文档以及 DataBricks 公司博文,本系列基本是中英双语,主要是为了提高自己的英语水平. 文章分类 spark databricks A Tale of Thre ...

  4. [python] ThreadPoolExecutor线程池 python 线程池

    初识 Python中已经有了threading模块,为什么还需要线程池呢,线程池又是什么东西呢?在介绍线程同步的信号量机制的时候,举得例子是爬虫的例子,需要控制同时爬取的线程数,例子中创建了20个线程 ...

  5. wireshark抓包分析工具的使用

    # wireshark抓包分析工具的使用 ## 常用抓包指令 - `ip.src==192.168.60.26 and ip.dst==111.7.187.220 and tcp.port == 80 ...

  6. Win10连接远程桌面的时候提示您的凭证不工作该怎么办?

    Win10连接远程桌面的时候提示您的凭证不工作该怎么办?Win10连接远程桌面的时候,提示“您的凭证不工作”.原有保存的远程帐号密码无法使用,导致远程登录系统失败.我这里总结下自己解决的方法,分享给大 ...

  7. Specified version of key is not available (44)

    -- ::, ERROR [HiveServer2-Handler-Pool: Thread-]: transport.TSaslTransport (TSaslTransport.java:open ...

  8. "title_activity_dist" is not translated in "zh-rCN" (Chinese: China)

    根据报错提示,是说我没有对string文件做国际化翻译操作,但是我报错的项目并没有做国际化,所以并没有values-zh-rCN和values-zh-rTW两个文件夹,最后我发现原来是当前项目引用的一 ...

  9. TIJ -- 吐司BlockingQueue

    1. 吐司BlockingQueue 考虑下面这个使用BlockingQueue的示例.有一台机器具有三个任务:一个制作吐司,一个给吐司抹黄油,另一个在抹过黄油的吐司上吐果酱.我们可以通过各个处理过程 ...

  10. array_walk 与 array_map的 区别

    1.array_walk是用于用户自定义的函数,所以想用array_walk($aIds, "trim");去掉数据元素中的空格是达不到目的的只能用array_walk($aIds ...