这是一道卡常好题

从160s卡到36s

qwq

由于题目设计到原数组的单点修改,那么就对应着前缀和数组上的区间加。

很显然能想到用线段树来维护这么个东西。

那么该如果求题目要求的位置呢

我们来看这个题的式子,他要求$$a_i = s_{i-1}$$

我们稍微变形一下$$s_i-s_{i-1}=s_{i-1}$$

\[s_i = 2\times s_{i-1}
\]

而且,由于\(a\)数组任意时刻都是非负的。所以\(s\)也是单调不下降的。

那我们就可以从\(1\)开始,然后每次找到第一个大于等于\(2*当前值\)的位置,看看是否合法,然后跳过去,继续下一次的过程。

这样可以严格证明复杂度是\(log\)的(可以理解为最多\(log\)次,就加到极限了)

int solve()
{
int now=0;
ll uu=0;
while(now!=n)
{
int nxt = getpos(1,1,n,2*uu);
//if (query(1,1,n,nxt-1)*2==query(1,1,n,nxt)) return nxt;
if(kachang == 2*a[nxt]) return nxt;
now=nxt;
uu=kachang;
}
return -1;
}

计算第一个大于等于某个数的过程,我们可以直接选择再线段树上二分,这样复杂度是\(log\)的,如果要是不在线段树上二分,可能需要两个\(log\)的时间

int getpos(int root,int l,int r,ll lim)
{
if (l==r)
{
kachang = f[root];
return l;
}
pushdown(root,l,r);
int mid = l+r >> 1;
if (f[root<<1]>=lim) return getpos(root<<1,l,mid,lim);
else return getpos(root<<1|1,mid+1,r,lim);
}

(而且这个题会卡常,我这里贴的代码都是卡常之后的,可能比较难理解)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 4e5+1e2;
ll f[4*maxn];
ll add[4*maxn];
int n,m;
int pos,ans;
ll sum[maxn],a[maxn];
void up(int root)
{
f[root]=max(f[root<<1],f[root<<1|1]);
}
void pushdown(int root,int l,int r)
{
if (add[root])
{
add[root<<1]+=add[root];
add[root<<1|1]+=add[root];
f[root<<1]+=add[root];
f[root<<1|1]+=add[root];
add[root]=0;
}
}
void build(int root,int l,int r)
{
if (l==r)
{
f[root]=sum[l];
return;
}
int mid = l+r >> 1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
up(root);
}
void update(int root,int l,int r,int x,int y,ll p)
{
if (x<=l && r<=y)
{
f[root]+=p;
add[root]+=p;
return;
}
pushdown(root,l,r);
int mid = l+r >> 1;
if (x<=mid) update(root<<1,l,mid,x,y,p);
if (y>mid) update(root<<1|1,mid+1,r,x,y,p);
up(root);
}
ll query(int root,int l,int r,int x)
{
if (x==0) return 0;
if (l==r)
{
return f[root];
}
pushdown(root,l,r);
int mid = l+r >> 1;
ll ans = -1e18;
if (x<=mid) ans=max(ans,query(root<<1,l,mid,x));
if (x>mid) ans=max(ans,query(root<<1|1,mid+1,r,x));
return ans;
}
long long kachang;
int getpos(int root,int l,int r,ll lim)
{
if (l==r)
{
kachang = f[root];
return l;
}
pushdown(root,l,r);
int mid = l+r >> 1;
if (f[root<<1]>=lim) return getpos(root<<1,l,mid,lim);
else return getpos(root<<1|1,mid+1,r,lim);
}
int solve()
{
int now=0;
ll uu=0;
while(now!=n)
{
int nxt = getpos(1,1,n,2*uu);
//if (query(1,1,n,nxt-1)*2==query(1,1,n,nxt)) return nxt;
if(kachang == 2*a[nxt]) return nxt;
now=nxt;
uu=kachang;
}
return -1;
}
signed main()
{
n=read();m=read();
for (register int i=1;i<=n;++i) a[i]=read();
for (register int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
build(1,1,n);
for (register int i=1;i<=m;++i)
{
int x=read(),y=read();
update(1,1,n,x,n,y-a[x]);
a[x]=y;
cout<<solve()<<"\n";
}
return 0;
}

CF992E Nastya and King-Shamans(线段树二分+思维)的更多相关文章

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

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

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

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

  3. hdu4614 线段树+二分 插花

    Alice is so popular that she can receive many flowers everyday. She has N vases numbered from 0 to N ...

  4. 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块

    !!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...

  5. luogu4422 [COCI2017-2018#1] Deda[线段树二分]

    讨论帖:线段树二分的题..我还考场切过..白学 这题我一年前的模拟赛考场还切过,现在就不会了..好菜啊. 显然直接线段树拆成$\log n$个区间,然后每个区间在进行线段树二分即可. UPD:复杂度分 ...

  6. bzoj4399 魔法少女LJJ 线段树合并+线段树二分+并查集

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4399 题解 毒瘤题 \(9\) 种操作还有支持动态图的连通性 仔细读题 $ c<=7$. ...

  7. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

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

  9. 洛谷$P2824\ [HEOI2016/TJOI2016]$ 排序 线段树+二分

    正解:线段树+二分 解题报告: 传送门$QwQ$ 昂着题好神噢我$jio$得$QwQQQQQ$,,, 开始看到长得很像之前考试题的亚子,,,然后仔细康康发现不一样昂$kk$,就这里范围是$[1,n]$ ...

随机推荐

  1. windows下mysql5.7.17配置

    1.官网下载mysql5.7.17 64位 https://dev.mysql.com/downloads/mysql/ 2.安装完解压到E盘主目录下,改文件名为mysql 3.配置环境变量 我的电脑 ...

  2. Mysql 5.6 编译报错

    编译安装 mysql(下面是编译参数) /usr/local/bin/cmake . -DCMAKE_INSTALL_PREFIX=/application/mysql-5.6.36 \ -DMYSQ ...

  3. 移动端ios上下滑动翻页事件失效

    移动端开发过程中,在添加上下滑动事件时候,引入了最常用的移动端库zepto.js及其touch模块,有一种现象,安卓的手机没有问题,上下滑动翻页很正常 :但是到了ios上面,好啊,上下滑动会出现弹性滚 ...

  4. IDEA中mybatis generator使用

    1.在对应服务的pom.xml文件中添加依赖 <build> <plugins> <plugin> <groupId>org.mybatis.gener ...

  5. mybaits源码分析--事务管理(八)

    一.事务管理 写到这也快进入收尾阶段了了,在介绍MyBatis中的事务管理时不可避免的要接触到DataSource的内容,所以接下来会分别来介绍DataSource和Transaction两块内容. ...

  6. 手写AVL平衡二叉搜索树

    手写AVL平衡二叉搜索树 二叉搜索树的局限性 先说一下什么是二叉搜索树,二叉树每个节点只有两个节点,二叉搜索树的每个左子节点的值小于其父节点的值,每个右子节点的值大于其左子节点的值.如下图: 二叉搜索 ...

  7. java多线程同步的5种方法

    一.为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会导致变量值或对象的状态出现混乱,从而导致程序异常. 举个例子,如果一个银行账户同时被两个线程 ...

  8. 控制台:控制台艺术字 & 为控制台输出增加样式(console.log( ))

    控制台/代码文档LOGO 除了知乎的控制台,大部分的代码文档都有这样的字符logo. 下面这个网站可以自动生成符号艺术字: Text to ASCII Art Generator (TAAG) 控制台 ...

  9. CommonsCollections1 反序列化利用链分析

    InvokerTransformer 首先来看 commons-collections-3.1-sources.jar!\org\apache\commons\collections\functors ...

  10. Spring Boot中有多个@Async异步任务时,记得做好线程池的隔离!

    通过上一篇:配置@Async异步任务的线程池的介绍,你应该已经了解到异步任务的执行背后有一个线程池来管理执行任务.为了控制异步任务的并发不影响到应用的正常运作,我们必须要对线程池做好相应的配置,防止资 ...