题目地址: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的更多相关文章

  1. CDQ分治与整体二分小结

    前言 这是一波强行总结. 下面是一波瞎比比. 这几天做了几道CDQ/整体二分,感觉自己做题速度好慢啊. 很多很显然的东西都看不出来 分治分不出来 打不出来 调不对 上午下午晚上的效率完全不一样啊. 完 ...

  2. CDQ分治与整体二分学习笔记

     CDQ分治部分 CDQ分治是用分治的方法解决一系列类似偏序问题的分治方法,一般可以用KD-tree.树套树或权值线段树代替. 三维偏序,是一种类似LIS的东西,但是LIS的关键字只有两个,数组下标和 ...

  3. CQD(陈丹琦)分治 & 整体二分——专题小结

    整体二分和CDQ分治 有一些问题很多时间都坑在斜率和凸壳上了么--感觉斜率和凸壳各种搞不懂-- 整体二分 整体二分的资料好像不是很多,我在网上找到了一篇不错的资料:       整体二分是个很神的东西 ...

  4. 一篇自己都看不懂的CDQ分治&整体二分学习笔记

    作为一个永不咕咕咕的博主,我来更笔记辣qaq CDQ分治 CDQ分治的思想还是比较简单的.它的基本流程是: \(1.\)将所有修改操作和查询操作按照时间顺序并在一起,形成一段序列.显然,会影响查询操作 ...

  5. [学习笔记]CDQ分治和整体二分

    序言 \(CDQ\) 分治和整体二分都是基于分治的思想,把复杂的问题拆分成许多可以简单求的解子问题.但是这两种算法必须离线处理,不能解决一些强制在线的题目.不过如果题目允许离线的话,这两种算法能把在线 ...

  6. Cdq分治整体二分学习记录

    这点东西前前后后拖了好几个星期才学会……还是自己太菜啊. Cdq分治的思想是:把问题序列分割成左右两个,先单独处理左边,再处理左边对右边的影响,再单独处理右边.这样可以消去数据结构上的一个log,降低 ...

  7. 【学时总结】◆学时·IX◆ 整体二分

    ◆学时·IX◆ 整体二分 至于我怎么了解到这个算法的……只是因为发现一道题,明显的二分查找,但是时间会爆炸,被逼无奈搜题解……然后就发现了一些东西QwQ ◇ 算法概述 整体二分大概是把BFS与二分查找 ...

  8. 整体二分learning

    整体二分是一个离线的做法  目前可以解决求区间第k大问题 当然划分树主席树都可以的样子.. 为什么我老学一些解决同种问题的算法.. 主要思想大概是这样的: 如果要求[l,r]的区间第K大 而这个区间内 ...

  9. 算法笔记--CDQ分治 && 整体二分

    参考:https://www.luogu.org/blog/Owencodeisking/post-xue-xi-bi-ji-cdq-fen-zhi-hu-zheng-ti-er-fen 前置技能:树 ...

随机推荐

  1. 某考试 T1 至危警告

    题目大意就是: 设f(x)为x各个位数字之和,求x属于[0,k]且b * f(x)^a + c = x的x个数并升序输出. (a<=5  .  b,c,<=10^4  .   k<= ...

  2. Java实现网页截屏

    原文:http://www.open-open.com/code/view/1424006089452 import java.awt.AWTException; import java.awt.De ...

  3. Meteor教程

    Meteor 是一个构建在 Node.js 之上的平台,用来开发实时网页程序.Meteor 程序位于数据库和用户界面之间,保持二者之间的数据同步更新. 因为 Meteor 是基于 Node.js 开发 ...

  4. 公布Java桌面程序

    我拿了一份桌面工具的开源码,修改动改,在elipse上执行.感觉良好.但到了公布应用程序,就傻眼了. 我竟然不知道咋公布! 呵呵,不愧是Java小白. 假设是微软阵营,直接就编译成exe了. 但jav ...

  5. Hadoop架构设计、执行原理具体解释

    1.Map-Reduce的逻辑过程 如果我们须要处理一批有关天气的数据.其格式例如以下: 依照ASCII码存储.每行一条记录 每一行字符从0開始计数,第15个到第18个字符为年 第25个到第29个字符 ...

  6. CSS 相对|绝对(relative/absolute)定位系列(一)

    一.有话要说 以前写内容基本上都是:眼睛一亮——哟呵,这个不错,写!然后去古人所说的茅房里蹲会儿,就有写作的思路了.但是,构思相对/绝对(relative/absolute)定位系列却有好些时日,考虑 ...

  7. 跟面试官讲Binder(零)

    面试的时候,面试官问你说,简单说一下Android的Binder机制,你会怎么回答? 我想,我会这么说. 在Android启动的时候,Zygote进程孵化出第一个子进程叫SystemServer,而在 ...

  8. Linux 简单的Shell输出

    echo:用于输出指定字符串或用于在Shell中打印Shell变量的值    语法格式:echo [选项] [参数]    -n:不输出换行 linlin@ubuntu:~/linlin/text$ ...

  9. [libcurl]_[0基础]_[使用libcurl下载大文件]

    场景: 1. 在Windows编程时, 下载http页面(html,xml)能够使用winhttp库,可是并非非常下载文件,由于会失败. 由此引出了WinINet库,无奈这个库的稳定性比較低,使用样例 ...

  10. 嵌入式开发之davinci--- DVRRDK, EZSDK和DVSDK这三者有什么区别

    下载的时候选择信息要避免security类型的产品,这个是要审查的. DVRRDK是专门针对DVR的开发包是非公开的,针对安防的客户定制的,效率要高. EZSDK是开放的版本架构上使用openmax可 ...