CodeForces992E 二分 + 树状数组(线段树)
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=0;register char c=getchar();for(;!isdigit(c);c=getchar()); for(;isdigit(c);now=now*10+c-'0',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-9; const int maxn = 2e5 + 10; const int maxm = 1e6 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; 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 = 0; for(;x > 0 ; x -= x & -x) ans += tree[x]; return ans;} void solve(){if(a[1] == 0) return (void)puts("1");int x = 1;while(x < N){LL sum = getsum(x) * 2;if(getsum(x + 1) == sum) return (void)printf("%d\n",x + 1);int ans = x,l = x + 1,r = N;while(l <= r){int m = (l + r) >> 1;if(getsum(m) < sum){ans = m;l = m + 1;}else{r = m - 1;}}if(ans > N) break;x = (x == ans)?ans + 1:ans;}puts("-1"); } int main() {Sca2(N,Q);for(int i = 1; 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 0; }
思路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=0;register char c=getchar();for(;!isdigit(c);c=getchar()); for(;isdigit(c);now=now*10+c-'0',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-9; const int maxn = 2e5 + 10; const int maxm = 1e6 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; 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 = 0;for(;p > 0; p -= p & -p) ans += fa[p];return ans; } struct Node{int pos;LL MAX;Node(int pos = 0,LL MAX = 0):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 << 2]; 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) >> 1;Build(t << 1,l,m); Build(t << 1 | 1,m + 1,r);tree[t].MAX = tree[t << 1].MAX + tree[t << 1 | 1].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) >> 1;if(pos <= m) update(t << 1,pos,val);else update(t << 1 | 1,pos,val);tree[t].MAX = tree[t << 1].MAX + tree[t << 1 | 1].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) >> 1;if(tree[t << 1].MAX.MAX >= sum) return query(t << 1,l,m,sum);return query(t << 1 | 1,m + 1,r,sum);}int m = (tree[t].l + tree[t].r) >> 1;if(r <= m) return query(t << 1,l,r,sum);else if(l > m) return query(t << 1 | 1,l,r,sum);else return query(t << 1,l,m,sum) - query(t << 1 | 1,m + 1,r,sum); }int solve(){if(getsum(1) == 0) return 1;int s = 1;while(s < N){LL now = getsum(s);Node MAX = query(1,s + 1,N,now);if(MAX.pos == INF) return -1;if(getsum(MAX.pos - 1) == MAX.MAX) return MAX.pos;s = MAX.pos;}return -1; } int main() {Sca2(N,Q);for(int i = 1; i <= N ; i ++){Scl(a[i]);add(i,a[i]);} Build(1,1,N);while(Q--){int x; LL p;scanf("%d%lld",&x,&p);update(1,x,p);add(x,p - a[x]); a[x] = p;Pri(solve()); }return 0; }
转载于:https://www.cnblogs.com/Hugh-Locke/p/9977966.html
CodeForces992E 二分 + 树状数组(线段树)相关推荐
- D-query SPOJ - DQUERY(求区间不同数的个数)(树状数组||线段树+离散)(主席树+在线)
English Vietnamese Given a sequence of n numbers a1, a2, -, an and a number of d-queries. A d-query ...
- HDU 1556 前缀和 树状数组 线段树
解法一: a[i]表示以 i作为起点,对 i-n的气球全部上色的次数 对(start,end)区间上色 ++a[start] --a[end+1]抵消掉 end+1-n的部分 问题转换为求 a的前缀 ...
- jzoj3854-分组【树状数组,线段树】
正题 题目链接:https://jzoj.net/senior/#contest/show/2990/2 题目大意 一个小队满足要求 队长的地位最高 所有队员和队长的年龄差不超过kkk 给出nnn个人 ...
- 模板三连击:树状数组+线段树+主席树
没事儿干,复习模板...... 1.树状数组 本来不想写这个的,但是反正就几分钟就打完了,所以就写了,水AC数. 洛谷 P3374 [模板]树状数组 1 1 #include<cstdio> ...
- 51nod 1680区间求和 (dp+树状数组/线段树)
不妨考虑已知一个区间[l,r]的k=1.k=2....k=r-l+1这些数的答案ans(只是这一个区间,不包含子区间) 那么如果加入一个新的数字a[i](i = r+1) 则新区间[l, i]的答案为 ...
- CCF201709-5 除法(100分)【树状数组+线段树】
试题编号: 201709-5 试题名称: 除法 时间限制: 10.0s 内存限制: 256.0MB 问题描述: 问题描述 小葱喜欢除法,所以他给了你N个数a1, a2, ⋯, aN,并且希望你执行M次 ...
- POJ2182 HDU2711 Lost Cows【树状数组+线段树】
Lost Cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 17113 Accepted: 10664 Descripti ...
- P2357 守墓人(树状数组/线段树)
题目描述 在一个荒凉的墓地上 有一个令人尊敬的守墓人, 他看守的墓地从来 没有被盗过, 所以人们很放心的把自己的先人的墓 安顿在他那 守墓人能看好这片墓地是必然而不是偶然..... 因为....守墓人 ...
- 差分+树状数组 线段树【P2357】 守墓人
题目描述-->p2357 守墓人 敲了一遍线段树,水过. 树状数组分析 主要思路: 差分 简单介绍一下差分(详细概念太麻烦,看下面. 给定一个数组 7 8 6 5 1 8 18 20 35 // ...
- [CSP-S模拟测试]:影魔(树状数组+线段树合并)
题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万. 千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄. 每一个灵魂,都有着 ...
最新文章
- face-swap.zip百度网盘下载
- android studio安装中出现Failed to install Intel HAXM错误的解决方法
- Atitit. 破解 拦截 绕过 网站 手机 短信 验证码 方式 v2 attilax 总结
- Java面试参考指南——同步
- DEV GridLookUpEdit属性设置
- 用碧海潮声制作的宋体(雅黑宋体)替换Windows7原生的火柴棍式的宋体
- 内核链表list.h文件剖析
- Codeforces Round #350 (Div. 2) B. Game of Robots 水题
- c#namespace
- 计算机图形学-----齐次坐标、空间变换矩阵和通用的建模方法
- 解决IE、firefox浏览器下JS的new Date()的值为Invalid Date、NaN-NaN的问题
- Overleaf 中文硕博论文LaTex模板
- 教学:四步利用PHP study小皮面板在vscode上编辑php并运行
- coco数据集大小分类_VOC、COCO数据集类别
- 谷歌高质量外链怎么做?Google网站买英文外链可行吗?
- python-opencv基础
- Clickhouse求时间差
- 【Matlab】删除cell中所有的空白cell
- 【详细】Python基础(一)
- dedecms织梦模板文件名介绍与说明
热门文章
- Anaconda tensorflow 安装笔记
- AsnycTask的内部的实现机制
- 使用scrapy的定制爬虫-第三章-爬虫的javascript支持
- [zz]Win8应用商店管理小工具
- Linux下TCP网络服务器实现源代码3
- SOA系列文章之(四):在Web服务中使用SOA
- Lucene和ES的关系
- php content type,PHP Content-type 的说明
- 华为5g鸿蒙麒麟,华为5G亮王牌:鸿蒙系统+7800W+麒麟990+防水,钱包按耐不住!
- 没有搜索_杭州诠网科技解析搜索词和点击量正常却没有咨询对话的原因