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. .net core compatibility windows & windows compatible Linux

    Who is this package for? This package is meant for developers that need to port existing .NET Framew ...

  2. AtCoder Beginner Contest 120 D - Decayed Bridges(并查集)

    题目链接:https://atcoder.jp/contests/abc120/tasks/abc120_d 题意 先给m条边,然后按顺序慢慢删掉边,求每一次删掉之后有多少对(i,j)不连通(我应该解 ...

  3. 前端传递给后端且通过cookie方式,尽量传递id

    前端传递给后端且通过cookie方式,尽量传递id

  4. Javascript和Jquery语法对比总结

    目的 相信大家都知道jq是js的一个类库,是为了方便我们开发前端,但是笔者在刚开始学习js和jq时经常将两者的语法记混和混用,所以整理下两者实现相同功能之前的语法区别. 声明变量 javascript ...

  5. U盘快速启动热键

    各个品牌电脑U盘快速启动热键如下:

  6. Codeforces 888G(分治+trie)

    按位贪心,以当前考虑位是0还是1将数分成两部分,则MST中这两部分之间只会存在一条边,因为一旦有两条或以上的边,考虑两条边在原图中所成的环,显然这两条边有一条是环上的权值最大边,不会出现在MST中.则 ...

  7. codeforces1101D GCD Counting 【树形DP】

    题目分析: 蛮简单的一道题,对于每个数拆质因子,对于每个质因子找出最长链,在每个地方枚举一下拼接 代码: #include<bits/stdc++.h> using namespace s ...

  8. 洛谷P1330封锁阳光大学题解

    题意 此题可以说是一个很裸的一个二分图染色,但是比较不同的是,这个图中可能是不联通的,因此我们需要找到所有的联通块,然后一一选出每个联通块中黑块与白块中最小的个数,然后加入到最后的答案中去,也是很坑的 ...

  9. Quartus prime 16.0 in_system memory content editor 使用

    前言 quartus提供了片内存储器的实时查看与修改,而不用编译工程,很棒.你可以方便的查看到存储器中到底存储了什么东西. 流程 1.打开: 2.主界面: 3.设置jtag项之后,查看即可. sign ...

  10. Codeforces Round #530 (Div. 2) A,B,C,D

    A. Snowball 链接:http://codeforces.com/contest/1099/problem/A 思路:模拟 代码: #include<bits/stdc++.h> ...