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 ...
随机推荐
- asp.net core mvc ajaxform submit files
<form id="form1" method="post" enctype="multipart/form-data" asp-co ...
- css中绝对定位和相对定位详解
相对定位relative和绝对定位absolute 相对定位 相对定位是标签在根据没加position样式前的位置来定位不会受父级标签的定位的影响,并且定位后不会脱离文本流,会占据原来的位置. 接下来 ...
- 前端部分-CSS基础介绍
CSS介绍 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素.也就是定义相应的标签语言来定制显示样式达到一定的显示效果. 每个CSS样式由两个组成部分:选择器和 ...
- 学习 Civil 3D二次开发从哪儿开始?
1.1 从哪儿开始 对于多数的工程设计人员,不完全具备上节所述的各种条件.对于Civil 3D的应用可能比较熟悉:但对于计算机语言,只限于上学时所学的一点基础知识,步入工作岗位后与计算机语言基本无缘: ...
- POJ2763-Housewife Wind-树上单点修改区间求和
这道题可以树链剖分做.但是最近在给学弟搞数据结构复习了LCA树状数组RMQ 然后就搞了一发LCA+树状数组维护. dis数组维护当前点到根节点的权值和.则dis(u,v) = dis[u]+dis[v ...
- 【XSY2753】Lcm 分治 FWT FFT 容斥
题目描述 给你\(n,k\),要你选一些互不相同的正整数,满足这些数的\(lcm\)为\(n\),且这些数的和为\(k\)的倍数. 求选择的方案数.对\(232792561\)取模. \(n\leq ...
- bzoj 2761: [JLOI2011]不重复数字 (map||Treap)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2761 思路: map标记 实现代码: #include<bits/stdc++.h&g ...
- PHP 公共方法分享180628
查看php 类的详情:方法.常量.属性( type(new \Illuminate\Http\Request());) /** * fixme 打印类详情 * @param $class object ...
- Qt Creator 搭配Git 版本控制
再次介绍一下Git的使用,这次是在Coding.net上部署项目的.这个是写给大作业合作的小伙伴们(我和我的A奶朋友们和某A的男朋友)看的. 安装Git 首先安装Git(msysGit) 下载地址 h ...
- 【dfs】LETTERS
1212:LETTERS [题目描述] 给出一个roe×colroe×col的大写字母矩阵,一开始的位置为左上角,你可以向上下左右四个方向移动,并且不能移向曾经经过的字母.问最多可以经过几个字母. [ ...