整体二分例题:POI2011Meteors——Chemist
题目地址:https://www.luogu.org/problemnew/show/P3527#sub
首先这个答案不是操作几次下了几场陨石雨之后的陨石个数,无法在线做,考虑离线做法。暴力的想法就是枚举每一场陨石雨,然后区间修改,每次判断没个国家的收集到的陨石个数是否大于等于需要的个数,枚举每一场陨石雨是O(k)的,区间修改是O(logm)的,枚举每一个国家是O(n)的,总时间复杂度是O(k*logm+k*n),显然超时。
我们知道时间复杂度的瓶颈主要是在每次枚举下到几场陨石雨时都需要扫一遍国家来判断,这可以用二分来做,而且这两部分都需要二分,于是就用整体二分来做。
首先我们要先二分答案,也就是第几场陨石雨,然后我们需要将所有的国家分为两部分,一部分是在这个二分的答案场陨石雨之前就可以收集到需要的陨石的国家,一部分是不能的国家。一旦我们找到一个精确的答案,也就是当二分的边界l==r时,就将这一次二分的L~R内的所有国家的答案设为这个答案。然后在具体判断时,每二分到一个答案,就将当前下的陨石雨的次数恢复到这个时刻,可以提前在1~m的范围内(也就是整个可能下陨石雨的范围内)建立树状数组,然后用树状数组实现,当当前的陨石雨的次数超过ans次时就一直减到ans次,反之同理。我们在一开始需要记录下每个国家所拥有的陨石收集器的位置,每次扫一煸这些位置,将它们各自收集到的陨石个数加起来,如果超过需要的那么这个答案一定可以,就往前面找,否则就不可以,往后找。但是需要注意的是每次需要更新往前找和往后找的国家的范围。而且由于此题是环的形式,所以需要分情况讨论:1.l<=r直接修改l~r。2.l>r修改l~m和1~r。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
int ans=;
char ch=getchar(),last=' ';
while(ch<''||ch>'')
{last=ch;ch=getchar();}
while(ch>=''&&ch<='')
{ans=ans*+ch-'';ch=getchar();}
if(last=='-')ans=-ans;
return ans;
}
const int M=,inf=1e9+;
vector<int>pos[M];
//pos[i]中储存第i个国家有的陨石收集器的位置
int n,m,k,num=;
int p[M],id[M],ans[M],tmp[M];
int l[M],r[M],val[M];//每场陨石场发生的区间和数量
bool ok[M];
ll c[M];//树状数组
int lowbit(int x)
{
return x&(-x);
}
ll sum(int x)
{
ll ans=;
while(x){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
void add(int x,int d)
{
while(x<=m){
c[x]+=d;
x+=lowbit(x);
}
}
void init()
{
n=read();m=read();
for(int i=;i<=m;i++){
int x=read();
pos[x].push_back(i);
}
for(int i=;i<=n;i++)
p[i]=read();
k=read();
for(int i=;i<=k;i++){
l[i]=read();r[i]=read();
val[i]=read();
}
k++;
l[k]=;r[k]=m;val[k]=inf;
for(int i=;i<=n;i++)
id[i]=i;
}
void doit(int x,int d)
{
if(l[x]<=r[x]){
add(l[x],val[x]*d);
add(r[x]+,val[x]*(-d));
}
//如果l<r直接修改这段区间
else{
add(,val[x]*d);
add(r[x]+,val[x]*(-d));
add(l[x],val[x]*d);
}
//如果l>r就修改1~r,l~m
}
void solve(int L,int R,int l,int r)
//L到R是答案处在l~r这一段区间的国家,l到r二分答案
{
if(L>R)return;
if(l==r)//如果找到答案,这一段区间的答案全部是这个答案
{
for(int i=L;i<=R;i++)
ans[id[i]]=l;
return;
}
int mid=(l+r)>>;
while(num+<=mid)doit(++num,);
while(num>mid)doit(num--,-);
int cnt=,x;
ll tot;
for(int i=L;i<=R;i++)
{
tot=;x=id[i];
int len=pos[x].size();
//len为这个国家陨石收集器的个数
for(int j=;j<len;j++){
tot+=sum(pos[x][j]);
if(tot>=p[x])break;
//如果已经收集到超过p[x]的陨石直接跳出
}
if(tot>=p[x])ok[x]=,cnt++;
else ok[x]=;
}
int l1=L,l2=L+cnt;
for(int i=L;i<=R;i++){
if(ok[id[i]])tmp[l1++]=id[i];
else tmp[l2++]=id[i];
}
for(int i=L;i<=R;i++)
id[i]=tmp[i];
solve(L,l1-,l,mid);
solve(l1,l2-,mid+,r);
}
int main()
{
init();
solve(,n,,k);
for(int i=;i<=n;i++){
if(ans[i]==k)printf("NIE\n");
else printf("%d\n",ans[i]);
}
return ;
}
整体二分例题:POI2011Meteors——Chemist的更多相关文章
- CDQ分治与整体二分小结
前言 这是一波强行总结. 下面是一波瞎比比. 这几天做了几道CDQ/整体二分,感觉自己做题速度好慢啊. 很多很显然的东西都看不出来 分治分不出来 打不出来 调不对 上午下午晚上的效率完全不一样啊. 完 ...
- CDQ分治与整体二分学习笔记
CDQ分治部分 CDQ分治是用分治的方法解决一系列类似偏序问题的分治方法,一般可以用KD-tree.树套树或权值线段树代替. 三维偏序,是一种类似LIS的东西,但是LIS的关键字只有两个,数组下标和 ...
- CQD(陈丹琦)分治 & 整体二分——专题小结
整体二分和CDQ分治 有一些问题很多时间都坑在斜率和凸壳上了么--感觉斜率和凸壳各种搞不懂-- 整体二分 整体二分的资料好像不是很多,我在网上找到了一篇不错的资料: 整体二分是个很神的东西 ...
- 一篇自己都看不懂的CDQ分治&整体二分学习笔记
作为一个永不咕咕咕的博主,我来更笔记辣qaq CDQ分治 CDQ分治的思想还是比较简单的.它的基本流程是: \(1.\)将所有修改操作和查询操作按照时间顺序并在一起,形成一段序列.显然,会影响查询操作 ...
- [学习笔记]CDQ分治和整体二分
序言 \(CDQ\) 分治和整体二分都是基于分治的思想,把复杂的问题拆分成许多可以简单求的解子问题.但是这两种算法必须离线处理,不能解决一些强制在线的题目.不过如果题目允许离线的话,这两种算法能把在线 ...
- Cdq分治整体二分学习记录
这点东西前前后后拖了好几个星期才学会……还是自己太菜啊. Cdq分治的思想是:把问题序列分割成左右两个,先单独处理左边,再处理左边对右边的影响,再单独处理右边.这样可以消去数据结构上的一个log,降低 ...
- 【学时总结】◆学时·IX◆ 整体二分
◆学时·IX◆ 整体二分 至于我怎么了解到这个算法的……只是因为发现一道题,明显的二分查找,但是时间会爆炸,被逼无奈搜题解……然后就发现了一些东西QwQ ◇ 算法概述 整体二分大概是把BFS与二分查找 ...
- 整体二分learning
整体二分是一个离线的做法 目前可以解决求区间第k大问题 当然划分树主席树都可以的样子.. 为什么我老学一些解决同种问题的算法.. 主要思想大概是这样的: 如果要求[l,r]的区间第K大 而这个区间内 ...
- 算法笔记--CDQ分治 && 整体二分
参考:https://www.luogu.org/blog/Owencodeisking/post-xue-xi-bi-ji-cdq-fen-zhi-hu-zheng-ti-er-fen 前置技能:树 ...
随机推荐
- [Noip复习知识点][个人向]Zackzh
只是列列一些要复习的,努力复习吧,有种noip退役的赶脚. 一.模拟 (这你也不会?退役吧) 二.DP 1.基础dp 2.区间dp 3.状压dp 4.树形dp 6.概率(期望)dp 7.环形dp 8. ...
- Maven使用tomcat7-maven-plugin插件run时出现错误: A child container failed during start java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component
错误如下: A child container failed during startjava.util.concurrent.ExecutionException: org.apache.catal ...
- java验证身份证号码是否有效源代码
原文:http://www.open-open.com/code/view/1420373343171 1.描述 用java语言判断身份证号码是否有效,地区码.出身年月.校验码等验证算法 2.源代码 ...
- Java实现拖拽上传
原文:http://www.open-open.com/code/view/1437358795584 在项目开发中由于实际需求,需要开发拖拽上传的功能,ok! 先看效果图: jsp上传前端代码: & ...
- arcengine 文件夹连接
Provides access to members that manages a GX catalog. Product Availability Available with ArcGIS Des ...
- discuz的php7版本号
php7的安装 wget http://am1.php.net/get/php-7.0.4.tar.gz/from/this/mirror tar zvxf php-7.0.4.tar.gz cd p ...
- System.Diagnostics.Debug.WriteLine 在OutPut中无输出
TextWriterTraceListener writer = new TextWriterTraceListener(System.Console.Out); Debug ...
- 算法导论学习之线性时间求第k小元素+堆思想求前k大元素
对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思 ...
- Linux —— 查找与替换
Linux —— 查找与替换 文本查找: grep, egrep, fgrep grep:根据基本正则表达式定义的模式搜索文档,并将符合模式的文本行显示出来 注意:搜索时属 ...
- 4448: [Scoi2015]情报传递|主席树|离线操作
能够把全部的操作离线,然后树链剖分将全部人搜集情报的时间增加到主席树中,查询的时候能够直接查询搜集情报时间≤i−C[i]−1的人的个数 时间复杂度n∗log22n,空间复杂度n∗log2n #incl ...