http://codeforces.com/problemset/problem/992/E

题意:给定一个序列 ai​ ,记其前缀和序列为 si​ ,有 q 个询问,每次单点修改,询问是否存在一个 i 满足 ai​=si−1​,有多解输出任意一个,无解输出 -1。

思路一:构造一个b[i] = a[i] - s[i - 1]的序列,答案就是在其中寻找为0的位置,对每一次操作进行一个线段树的单点修改和区间修改之后对一整个区间寻找是否存在0的位置,但是最坏的情况下能达到N * Q * lnN,虽然据说可过但是觉得并不靠谱

思路2:ai = si - 1,考虑转化一下就变成了si = 2 * s(i - 1),所以对于起始位置x,下一个可能符合答案ans - 1的位置的就是最大的sk < 2 * sx,因为x到k中间的位置很显然前一个数的s会比sx大,后一个数的位置会比sk小,很显然并不满足。

所以可以考虑用树状数组维护前缀和之后用一个类似跳的算法加一个二分寻找ans,时间复杂度是QlnNlnNlnN,有点慢但依然可以过。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = 2e5 + ;
const int maxm = 1e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,Q;
LL a[maxn];
LL tree[maxn];
void add(int x,int t){for(;x <= N ; x += x & -x) tree[x] += t;}
LL getsum(int x){LL ans = ; for(;x > ; x -= x & -x) ans += tree[x]; return ans;}
void solve(){
if(a[] == ) return (void)puts("");
int x = ;
while(x < N){
LL sum = getsum(x) * ;
if(getsum(x + ) == sum) return (void)printf("%d\n",x + );
int ans = x,l = x + ,r = N;
while(l <= r){
int m = (l + r) >> ;
if(getsum(m) < sum){
ans = m;
l = m + ;
}else{
r = m - ;
}
}
if(ans > N) break;
x = (x == ans)?ans + :ans;
}
puts("-1");
}
int main()
{
Sca2(N,Q);
for(int i = ; i <= N ; i ++){
Scl(a[i]); add(i,a[i]);
}
while(Q--){
int x; LL p;
scanf("%d%lld",&x,&p);
add(x,p - a[x]); a[x] = p;
solve();
} return ;
}

思路2

思路3:将跳的思路改为寻找一个最小的大于si的位置,考虑用线段树维护一下区间最大值,树状数组维护前缀和,可以优化掉一个ln

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = 2e5 + ;
const int maxm = 1e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,Q;
LL fa[maxn],a[maxn];
void add(int p,int t){
for(;p <= N ; p += p & -p) fa[p] += t;
}
LL getsum(int p){
LL ans = ;
for(;p > ; p -= p & -p) ans += fa[p];
return ans;
}
struct Node{
int pos;
LL MAX;
Node(int pos = ,LL MAX = ):pos(pos),MAX(MAX) {}
};
Node operator + (Node a,Node b){
if(a.MAX >= b.MAX) return a;
return b;
}
Node operator - (Node a,Node b){
if(a.pos >= b.pos) return b;
return a;
}
struct Tree{
int l,r;
Node MAX;
}tree[maxn << ];
void Build(int t,int l,int r){
tree[t].l = l; tree[t].r = r;
if(l == r){
tree[t].MAX.MAX = a[l];
tree[t].MAX.pos = l;
return;
}
int m = (l + r) >> ;
Build(t << ,l,m); Build(t << | ,m + ,r);
tree[t].MAX = tree[t << ].MAX + tree[t << | ].MAX;
}
void update(int t,int pos,LL val){
if(tree[t].l == tree[t].r){
tree[t].MAX.MAX = val;
return;
}
int m = (tree[t].l + tree[t].r) >> ;
if(pos <= m) update(t << ,pos,val);
else update(t << | ,pos,val);
tree[t].MAX = tree[t << ].MAX + tree[t << | ].MAX;
}
Node query(int t,int l,int r,LL sum){
if(l <= tree[t].l && tree[t].r <= r){
if(tree[t].MAX.MAX < sum) return Node(INF,1e18);
if(tree[t].l == tree[t].r) return tree[t].MAX;
int m = (tree[t].l + tree[t].r) >> ;
if(tree[t << ].MAX.MAX >= sum) return query(t << ,l,m,sum);
return query(t << | ,m + ,r,sum);
}
int m = (tree[t].l + tree[t].r) >> ;
if(r <= m) return query(t << ,l,r,sum);
else if(l > m) return query(t << | ,l,r,sum);
else return query(t << ,l,m,sum) - query(t << | ,m + ,r,sum);
} int solve(){
if(getsum() == ) return ;
int s = ;
while(s < N){
LL now = getsum(s);
Node MAX = query(,s + ,N,now);
if(MAX.pos == INF) return -;
if(getsum(MAX.pos - ) == MAX.MAX) return MAX.pos;
s = MAX.pos;
}
return -;
}
int main()
{
Sca2(N,Q);
for(int i = ; i <= N ; i ++){
Scl(a[i]);
add(i,a[i]);
}
Build(,,N);
while(Q--){
int x; LL p;
scanf("%d%lld",&x,&p);
update(,x,p);
add(x,p - a[x]); a[x] = p;
Pri(solve());
}
return ;
}

CodeForces992E 二分 + 树状数组(线段树)的更多相关文章

  1. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

  2. 树状数组 && 线段树应用 -- 求逆序数

    参考:算法学习(二)——树状数组求逆序数 .线段树或树状数组求逆序数(附例题) 应用树状数组 || 线段树求逆序数是一种很巧妙的技巧,这个技巧的关键在于如何把原来单纯的求区间和操作转换为 求小于等于a ...

  3. hdu1394(枚举/树状数组/线段树单点更新&区间求和)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 ...

  4. hdu 1166:敌兵布阵(树状数组 / 线段树,入门练习题)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  5. hdu 5147 Sequence II【树状数组/线段树】

    Sequence IITime Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem ...

  6. BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)

    题目链接 BZOJ 洛谷 整体二分求的是第K小(利用树状数组).求第K大可以转为求第\(n-K+1\)小,但是这样好像得求一个\(n\). 注意到所有数的绝对值\(\leq N\),将所有数的大小关系 ...

  7. 二分+树状数组/线段树(区间更新) HDOJ 4339 Query

    题目传送门 题意:给两串字符串,操作1:替换其中一个字符串的某个位置的字符 操作2:查询从p开始相等的最长连续长度 分析:树状数组可以维护一个区间内公共长度(连续)的情况,查询时用二分查找最远的端点即 ...

  8. Color the ball(树状数组+线段树+二分)

    Color the ball Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Tota ...

  9. Holedox Eating HDU - 4302 2012多校C 二分查找+树状数组/线段树优化

    题意 一个长度$n<=1e5$的数轴,$m<=1e5$个操作 有两种一些操作 $0$  $x$ 在$x$放一个食物 $1$ 一个虫子去吃最近的食物,如果有两个食物一样近,不转变方向的去吃 ...

  10. 第十四个目标(dp + 树状数组 + 线段树)

    Problem 2236 第十四个目标 Accept: 17    Submit: 35 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Probl ...

随机推荐

  1. Centos 7安装和配置 ElasticSearch入门小白

    实验环境: 操作系统:Centos 7.5 服务器ip:192.168.1.198 运行用户:root 网络环境:Internet 在企业生产环境有很多服务器的时候.很多业务模块的日志的时候运维人员需 ...

  2. Node.js机制及原理理解初步【转】

    一.node.js优缺点 node.js是单线程. 好处就是 1)简单 2)高性能,避免了频繁的线程切换开销 3)占用资源小,因为是单线程,在大负荷情况下,对内存占用仍然很低 3)线程安全,没有加锁. ...

  3. BZOJ2521[Shoi2010]最小生成树——最小割

    题目描述 Secsa最近对最小生成树问题特别感兴趣.他已经知道如果要去求出一个n个点.m条边的无向图的最小生成树有一个Krustal算法和另一个Prim的算法.另外,他还知道,某一个图可能有多种不同的 ...

  4. HDU5769-Substring-多校#4-1006-后缀数组

    给定一个字符x和一个字符串.要求输出包含此字符的所有不同字串. 后缀数组可以计算一个字符串的所有不同字串,理解了原理就能做这题了. 对于每一个后缀i,将产生len-sa[i]-hight[i]的前缀, ...

  5. linux统计使用最多的10个命令

    # cat /root/.bash_history  | awk '{print $1}' | sort | uniq -c | sort -nr | head history      查看命令历史 ...

  6. 【转】WEB服务器与应用服务器的区别

    https://blog.csdn.net/liupeng900605/article/details/7661406 一.简述 WEB服务器与应用服务器的区别: 1.WEB服务器: 理解WEB服务器 ...

  7. 20165223 结对编程之四则运算week2-整体总结

    目录 一.结对对象 二.需求分析 三.设计思路 四.核心代码 五.功能截图 六.结对感受 一.结对对象 担任角色(本周交换角色,流动学习) 驾驶员(Driver):20165218 赵冰雨(是控制键盘 ...

  8. spring代码异常捕获到logback logging.config=logback-spring.xml文件中不能输出异常e.printStackTrace

    在spring中使用logging.config=logback-spring.xml将日志转存到了文件中.但是代码中的捕获的异常无法用 e.printStackTrace 打印到文件中.使用如下方法 ...

  9. js 字符与ASCII码互转

    将字符转为ASCII码 var str = "A"; str.charCodeAt(); var str1 = 'a'; str1.charCodeAt(); 将ASCII码转为字 ...

  10. OpenLayers学习笔记(五)— 拖拽Feature图层

    参考文档的例子可以知道如何拖动矢量图层feature GitHub: 八至 作者:狐狸家的鱼 本文链接:拖拽Feature图层 全部代码 <!DOCTYPE html> <html& ...