题目地址: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. 2017多校Round4(hdu6067~hdu6079)

    补题进度:10/13 1001 待填坑 1002(kmp+递推) 题意: 有长度为n(<=50000)的字符串S和长度为m(m<=100)的字符串T,有k(k<=50000)组询问, ...

  2. 基于gulp编写的一个简单实用的前端开发环境

    自从Node.js出现以来,基于其的前端开发的工具框架也越来越多了,从Grunt到Gulp再到现在很火的WebPack,所有的这些新的东西的出现都极大的解放了我们在前端领域的开发,作为一个在前端领域里 ...

  3. Hexo搭建个人blog

    Hexo搭建 现在只想说心累... 前几天看了几个牛人的blog,感觉他们的风格很舒服,然后就发现了Hexo这个好东西!激动的想马上自己也弄一个,昨天晚上开始看资料特别是:潘柏信写了两篇 HEXO搭建 ...

  4. 接口测试工具--Fiddler 的使用

    代码部分 Rules -> Customize Rules  打开Fiddler ScriptEditor,这里可以通过修改脚本中某些方法( OnBeforeRequest(oSession: ...

  5. 10.2.0.1.1 grid control的启动和关闭

    一.Stopping Grid Control and All Its Components 1.停止OMS服务 [oracle@ocm2 oms10g]$ cd /u01/app/oracle/Or ...

  6. 初探swift语言的学习笔记十一(performSelector)

    作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/35842441 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...

  7. git clone新项目后如何拉取其他分支代码到本地

    1.git clone git@git.n.xxx.com:xxx/xxx.git 2.git fetch origin dev 命令来把远程dev分支拉到本地 - - 解读:git fetch命令用 ...

  8. [IT学习]阿铭Linux 微信公众号 每日一题 解析

    1.shell习题171020公布的昨日答案 习题171019 - 打印正方形 #!/bin/bash read -p "please input a number:" sum a ...

  9. android.view.View

    * This class represents the basic building block for user interface components. A View * occupies a ...

  10. 2016/3/10 PHP (超文本预处理器) 是什么?

    PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,利于学习,使用广泛,主要适用于W ...