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=;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 二分 + 树状数组(线段树)的更多相关文章
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- 树状数组 && 线段树应用 -- 求逆序数
参考:算法学习(二)——树状数组求逆序数 .线段树或树状数组求逆序数(附例题) 应用树状数组 || 线段树求逆序数是一种很巧妙的技巧,这个技巧的关键在于如何把原来单纯的求区间和操作转换为 求小于等于a ...
- hdu1394(枚举/树状数组/线段树单点更新&区间求和)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 ...
- hdu 1166:敌兵布阵(树状数组 / 线段树,入门练习题)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- hdu 5147 Sequence II【树状数组/线段树】
Sequence IITime Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem ...
- BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)
题目链接 BZOJ 洛谷 整体二分求的是第K小(利用树状数组).求第K大可以转为求第\(n-K+1\)小,但是这样好像得求一个\(n\). 注意到所有数的绝对值\(\leq N\),将所有数的大小关系 ...
- 二分+树状数组/线段树(区间更新) HDOJ 4339 Query
题目传送门 题意:给两串字符串,操作1:替换其中一个字符串的某个位置的字符 操作2:查询从p开始相等的最长连续长度 分析:树状数组可以维护一个区间内公共长度(连续)的情况,查询时用二分查找最远的端点即 ...
- Color the ball(树状数组+线段树+二分)
Color the ball Time Limit : 9000/3000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Tota ...
- Holedox Eating HDU - 4302 2012多校C 二分查找+树状数组/线段树优化
题意 一个长度$n<=1e5$的数轴,$m<=1e5$个操作 有两种一些操作 $0$ $x$ 在$x$放一个食物 $1$ 一个虫子去吃最近的食物,如果有两个食物一样近,不转变方向的去吃 ...
- 第十四个目标(dp + 树状数组 + 线段树)
Problem 2236 第十四个目标 Accept: 17 Submit: 35 Time Limit: 1000 mSec Memory Limit : 32768 KB Probl ...
随机推荐
- 数据同步到redis中时候需要 需要给关联的表增加id 如果是一对多 则增加list存储id 如果是一个 则增加一个字段 ;目的是便于取值
- bzoj-1191(二分图最大匹配)
解题思路:比较裸的一道题,直接跑匈牙利就行了,但是要注意一点,这个兔崽子是在闯关,一道题回答不出来就没了,直接在题目循环那里加一个else break;就行了!!!; #include<iost ...
- Servlet篇 之 web服务器
创建web项目,在web项目中创建html页面,然后把项目部署到web服务器里面,启动服务器之后,可以使用浏览器通过URL地址的方式,访问到web项目中的html页面了 Web服务器: 常用tomca ...
- BZOJ2150部落战争——最小路径覆盖
题目描述 lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一 个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住.lanzerb ...
- [IOI2018]高速公路收费——二分查找+bfs
题目链接: IOI2018highway 题目大意:给出一张$n$个点$m$条边的无向图,并给出一对未知的起点和终点,每条边都有两种边权$A$和$B$(每条边的$A$和$B$都分别相同),每次你可以设 ...
- 戴尔服务器H330阵列卡取消磁盘阵列教程
一:服务器开机看到ctrl+R提示,按ctrl+r进入阵列卡配置界面 二:按ctrl+N 转到PD Mgmt查看硬盘信息,确认硬盘状态:Ready 三:光标移到需配置硬盘上,按F2,选择 conver ...
- Tarjan求强连通分量,缩点,割点
Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点. 而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并 ...
- HDU2204 Eddy's爱好
题意:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数. 解析:一个数N 开K次根后得到M 则小于M的所有数的K次方一定小于N 因为任何一个合数都能分解为素数的乘积 所 ...
- 【XSY1538】连在一起的幻想乡 数学 无向连通图计数
题目大意 给你\(n,p\),求\(n\)个点组成的所有无向连通图的边数的平方和模\(p\) \(n\leq 2000,p\leq {10}^9\) 题解 设\(m=\frac{n(n-1 ...
- git 本地推送远程仓库报错: error: failed to push some refs to 'https://github.com/yangtuothink/mxonline.git'
报错现象 添加远程仓库后 推送代码的时候报错 报错分析 远程代码和本地代码不匹配问题 远程初始仓库的创建有些默认 的 README什么的本地是没有的 需要先同步后再上传 报错解决 git push - ...