这是一道卡常好题

从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. go协程调度

    目录 前言 1. 线程池的缺陷 2.Goroutine 调度器 3.调度策略 3.1 队列轮转 3.2 系统调用 3.3 工作量窃取 4.GOMAXPROCS设置对性能的影响 参考 前言 Gorout ...

  2. 详细解读go语言中的map

    Map map底层是由哈希表实现的 Go使用链地址法来解决键冲突. map本质上是一个指针,指向hmap 这里的buckets就是桶,bmap 每一个bucket最多可以放8个键值对,但是为了让内存排 ...

  3. cs_play

    # -*-coding:utf-8-*-__author__ = "logan.xu"###构造函数#class Role:# n = 123# # 类变量 比如 n = 123# ...

  4. eslint and stylelint config

    eslint: module.exports = {   root: true,   env: {     browser: true,     es6: true,     node: true   ...

  5. rsync 服务搭建

    rsync 服务搭建 服务端部署操作内容: 创建rsync用户和用户组 eg: useradd -s /sbin/nologin -M rsync 创建需要备份的指定目录,并修改权限 eg: mkdi ...

  6. MySQL——SQL语句入门

    1.DDL: 数据库定义语言 定义对象:库.表 何为定义: 库的定义: 创建 删除 修改---->修改本身以及库中的对象(表.视图.函数.触发器...) 表的定义: 创建---->定义表的 ...

  7. 各种插值法的python实现

    一维插值 插值不同于拟合.插值函数经过样本点,拟合函数一般基于最小二乘法尽量靠近所有样本点穿过.常见插值方法有拉格朗日插值法.分段插值法.样条插值法. 拉格朗日插值多项式:当节点数n较大时,拉格朗日插 ...

  8. 硕盟SM-A44|USB3.0转RJ45千兆网口转换器(TYPE A USB3.0 TO RJ45)

    硕盟SM-A44是一款USB3.0转RJ45千兆网口转换器.,转换USB端口到以太网端口.它让你投入低成本就可以轻松拥有千兆以太网.可将网络连接到台式机,笔记本电脑等等设备.硕盟 USB千兆网卡采用嵌 ...

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

    在 ysoserial中 commons-collections2 是用的 PriorityQueue reaObject 作为反序列化的入口 那么就来看一下 java.util.PriorityQu ...

  10. springmvc配置过程中遇到的一些问题总结

    springmvc配置过程中遇到的一些问题总结 1.配置tomcat过程中的错误: 2.配置web.xml中DispatchServlet报红(配置好已有依赖条件下) 解决的办法: 因为新添加依赖,m ...