CF1136E Nastya Hasn't Written a Legend(线段树)

还能说什么呢,简直太妙了。

$$a_{i+1}<a_i+k_i$$

$$a_{i+1}-k_i-k_{i-1}-\cdots-k_1<a_i+k_i-k_i-k_{i-1}-\cdots-k_1$$

$$a_{i+1}-k_i-k_{i-1}-\cdots-k_1<a_i-k_{i-1}-\cdots-k_1$$

令 $k$ 的前缀和为 $kpre$。

$$a_{i+1}-kpre_i<a_i-kpre_{i-1}$$

令 $b_i=a_i-kpre_{i-1}$。

$$b_{i+1}<b_i$$

也就是 $b$ 应该是单调不降的。

询问,经典操作。注意要加回一些 $kpre$。具体要再开一个 $kpre$ 的前缀和 $kprepre$。

修改,可以线段树上二分,找到最后一个 $\le val$ 的值,区间覆盖即可。

时间复杂度 $O(n+q\log n)$。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
const ll INF=9e18;
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(ch<‘0‘ || ch>‘9‘) f|=ch==‘-‘,ch=getchar();
    while(ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return f?-x:x;
}
int n,q,a[maxn],k[maxn];
ll kpre[maxn],kprepre[maxn],b[maxn],sum[maxn*4],L[maxn*4],R[maxn*4],cov[maxn*4];
char op[5];
inline int pushup(int o){
    sum[o]=sum[o<<1]+sum[o<<1|1];
    L[o]=L[o<<1];
    R[o]=R[o<<1|1];
}
inline void cover(int o,int l,int r,ll x){
    sum[o]=(r-l+1)*x;
    L[o]=R[o]=cov[o]=x;
}
inline void pushdown(int o,int l,int r){
    if(cov[o]!=-INF){
        int mid=(l+r)>>1;
        cover(lson,cov[o]);
        cover(rson,cov[o]);
        cov[o]=-INF;
    }
}
void build(int o,int l,int r){
    cov[o]=-INF;
    if(l==r) return void(sum[o]=L[o]=R[o]=b[l]);
    pushdown(o,l,r);
    int mid=(l+r)>>1;
    build(lson);build(rson);
    pushup(o);
}
ll query(int o,int l,int r,int ql,int qr){
    if(l>=ql && r<=qr) return sum[o];
    pushdown(o,l,r);
    int mid=(l+r)>>1;
    ll s=0;
    if(mid>=ql) s+=query(lson,ql,qr);
    if(mid<qr) s+=query(rson,ql,qr);
    return s;
}
void update(int o,int l,int r,int p,ll v){
    if(r<p || L[o]>v) return;
    if(l>=p && R[o]<=v) return cover(o,l,r,v);
    pushdown(o,l,r);
    int mid=(l+r)>>1;
    update(lson,p,v);update(rson,p,v);
    pushup(o);
}
int main(){
    n=read();
    FOR(i,1,n) a[i]=read();
    FOR(i,1,n-1) k[i]=read();
    FOR(i,1,n-1) kpre[i]=kpre[i-1]+k[i];
    FOR(i,1,n-1) kprepre[i]=kprepre[i-1]+kpre[i];
    FOR(i,1,n) b[i]=a[i]-kpre[i-1];
    build(1,1,n);
    q=read();
    while(q--){
        scanf("%s",op+1);
        int x=read(),y=read();
        if(op[1]==‘+‘) update(1,1,n,x,query(1,1,n,x,x)+y);
        else cout<<query(1,1,n,x,y)+kprepre[y-1]-kprepre[max(0,x-2)]<<endl;
    }
}

CF1136E Nastya Hasn't Written a Legend(线段树)

原文地址:https://www.cnblogs.com/1000Suns/p/11116677.html

时间: 2024-08-30 14:02:00

CF1136E Nastya Hasn't Written a Legend(线段树)的相关文章

Codeforces 1136E Nastya Hasn&#39;t Written a Legend (线段树教做人系列)

题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后,a[i + 1]<a[i] + k[i],那么a[i + 1]就变成a[i] + k[i],否则不变.同理,若a[i + 2]小于了现在的a[i + 1] + k[i + 1],那么a[i + 2]也变成a[i + 1] + k[i + 1],一直保持这个性质.第二章操作,询问数组a的区间[l, r]的

Nastya Hasn&#39;t Written a Legend(Codeforces Round #546 (Div. 2)E+线段树)

题目链接 传送门 题面 题意 给你一个\(a\)数组和一个\(k\)数组,进行\(q\)次操作,操作分为两种: 将\(a_i\)增加\(x\),此时如果\(a_{i+1}<a_i+k_i\),那么就将\(a_{i+1}\)变成\(a_i+k_i\),如果\(a_{i+2}<a_i+k_i\),则将\(a_{i+2}\)变成\(a_{i+1}+k_{i+1}\),以此类推. 查询\(\sum\limits_{i=l}^{r}a_i\). 思路 我们首先存下\(k\)数组的前缀和\(sum1\),

[cf 1136] E. Nastya Hasn&#39;t Written a Legend

题意 给两个数组分别为\(a\)和\(k\),有若干次操作: 1.给\(a_x\)加上\(y\),并以此对\(a_{x + i}(i \ge 1)\)赋值为\(\max \{a_{x + i}, a_{x + i - 1} + k_{x + i - 1}\}\). 2.询问区间\([l, r]\)的\(a_i\)的和. 题解 自闭了啊. 考虑把原序列分成若干个块,对于每个块内必须满足,除最后一个位置的所有位置\(i\),\(a_i + k_i = a_i + 1\).刚开始可以看成有\(n\)个

codeforces 1136E-Nastya Hasn&#39;t Written a Legend

传送门:QAQQAQ 题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后,a[i + 1]<a[i] + k[i],那么a[i + 1]就变成a[i] + k[i],否则不变.同理,若a[i + 2]小于了现在的a[i + 1] + k[i + 1],那么a[i + 2]也变成a[i + 1] + k[i + 1],一直保持这个性质.第二章操作,询问数组

Nastya and King-Shamans CodeForces - 992E (线段树二分)

大意: 给定序列a, 单点更新, 询问是否存在a[i]等于s[i-1], s为a的前缀和, a非负 考虑到前缀和的单调性, 枚举从1开始前缀和, 找到第一个大于等于s[1]的a[i], 如果相等直接输出. 若不满足则只能在a[i]的右侧, 此时前缀和为s[i], 至少为s[1]的两倍, 故最多进行log次. 具体实现的话, 线段树维护a与s的差, 二分找第一个非负即可, 复杂度$O(nlog^2n)$. #include <iostream> #include <algorithm>

HDOJ 5338 ZZX and Permutations 线段树+树状数组

[题意]: 给一个排列加上表示循环的括号,问如何让1到n的对应的字典序最大. 从1开始贪心每个数字可以往三个地方走,右边第一个,跳转到左边的某一个,和自己构成循环 对于走到右边第一个的情况,只要判断右边的那个有没有被占据就可以了,如果可以和右边的互换,那么需要在线段树中将右边的数置为0 跳转到左边的某一个,一个数如果跳转到左边的某一个则说明左边的那个是括号开头这个数是括号结尾,用一个线段树查询区间里的最大值,由于括号间是不能重叠的,所以需要用树状数组二分一下左边界.如果这个数是要跳转到左边的某个

hdu4288 离线处理线段树

http://acm.hdu.edu.cn/showproblem.php?pid=4288 Problem Description In mathematics and computer science, an algorithm describes a set of procedures or instructions that define a procedure. The term has become increasing popular since the advent of che

Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq

B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/427/B Description The prison of your city has n prisoners. As the prison can't accommodate all of them, the city mayor has decided to transfer c

POJ1195 Mobile phones 【二维线段树】

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14291   Accepted: 6644 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The