整体二分例题: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 前置技能:树 ...
随机推荐
- Fractal---POJ2083(dfs)
http://poj.org/problem?id=2083 一道我认为有点恶心的dfs 刚开始没有初始化 用G++交 一直TLE 后来用了C++竟然是wa 那这肯定是我的问题了 ...
- [Noip复习知识点][个人向]Zackzh
只是列列一些要复习的,努力复习吧,有种noip退役的赶脚. 一.模拟 (这你也不会?退役吧) 二.DP 1.基础dp 2.区间dp 3.状压dp 4.树形dp 6.概率(期望)dp 7.环形dp 8. ...
- codeforces 892E(离散化+可撤销并查集)
题意 给出一个n个点m条边的无向联通图(n,m<=5e5),有q(q<=5e5)个询问 每个询问询问一个边集{Ei},回答这些边能否在同一个最小生成树中 分析 要知道一个性质,就是权值不同 ...
- JAVA实现选择排序,插入排序,冒泡排序,以及两个有序数组的合并
一直到大四才开始写自己的第一篇博客,说来实在有点羞愧.今天写了关于排序的算法题,有插入排序,冒泡排序,选择排序,以下贴上用JAVA实现的代码: public class test5 { public ...
- Java实验——输出二维数组连续二维子数组的最大和
该算法思路,根据我博客里面一维子数组求和的思路,可以用一个新的二维数组对该二维区域的数组进行求和,例如新的二维数组的第5个位置,就代表从1到5斜对角线的块状区域的和,即1,2,4,5这4个数的和,x个 ...
- Spring的JDBC示例
以下内容引用自http://wiki.jikexueyuan.com/project/spring/jdbc-framework-overview/spring-jdbc-example.html: ...
- TDBXJSONStream(BERLIN新增)的使用
DELPHI 10.1 BERLIN新增TDBXJSONStream类,用于方便地将数据序列为JSON,和将JSON还原出来数据. DATASNAP远程方法也相应地增加了支持返回TDBXJSONStr ...
- burpsuite破解版
来源:http://www.vuln.cn/8847
- python第四讲
三元运算符: 三元运算又叫三目运算,是对简单的条件语句的缩写. 书写格式: n1 = 值1 if 条件 else 值2 # 如果条件成立,那么将 “值1” 赋值给n1变量,否则,将“值2”赋值给n1变 ...
- linux nginx service nginx restart [fail]
命令:nginx -t 查看失败原因: nginx: [emerg] "fastcgi_pass" directive is duplicate in /etc/nginx/sit ...