Meteors 题解
蒟蒻初学整体二分,写一篇题解记录一下思考与看法。
题目大意
在一个环形的轨道上分别着若干国家的空间站,在接下来的一段时间内会出现若干次陨石,每次出现在环形的某一段轨道,每个国家都想收集一定量的陨石,需要判断每个国家最少在什么时候可以集齐所需的陨石。
思路分析
首先可以想到一个简单而暴力的做法:
枚举每一个国家,逐一将每一次陨石落下,判断其在哪一个时间收集满了所需的陨石。
但这样的时间复杂度是 \(O(n^2)\)(令 \(n,m,k\) 同阶)的,没有办法解决这个问题。
需要更优的解法!
容易发现,对于每一个国家,答案都是单调不降的,这启示我们可以使用二分!
那么我们首先会想到,对于每一个国家,二分其收集满陨石的时刻。
但这样的时间复杂度是 \(O(n^2\log n)\) 的,甚至还没有暴力优秀。
因此,我们需要转化思考角度。
我们发现,在对于每个国家进行二分时,我们都降落了很多次陨石(平均 \(n\log n\) 次),这肯定是巨亏的,那么,我们是否可以不枚举国家进行降落陨石,而是改为降落陨石,枚举每个国家的时间呢?
这时,整体二分就闪亮登场了!
整体二分的思想是将很多个需要二分的对象放在一起,通过改变枚举对象来达到优化时间复杂度的目标。
比如在这题中,我们可以将所有的国家放在一起进行二分,在二分时只降落区间中点前半部分的陨石,在查询每个国家是否收集满,并以此将其划分到子区间中。
具体的说,我们设计函数 solve(l,r,x,y)
表示 \([l,r]\) 的陨石对 \([x,y]\) 的国家的贡献。(比较抽象?感性理解)
首先考虑边界,当 \(l=r\) 时,我们可以确定答案。
否则,我们另 \(\text{mid}=\frac{l+r}{2}\),将从 \(l\) 到 \(\text{mid}\) 之间的陨石全部降落,并将这个区间的所有的国家进行判断,如果已经收集满了,我们就将它划分到左区间中,否则划分到右区间中。
这样递归下去我们就可以得到所有国家的答案了!
时间复杂度?我们需要递归 \(\log n\) 层,每层需要把一半的陨石降落,陨石降落是一个区间操作,我们可以通过一个数据结构将降落过程优化到 \(\log n\) 级别,因此整体二分的时间复杂度是 \(O(n\log^2n)\) 的。(是不是比之前的做法优秀许多?)
整体二分的思想比较有意思,它通过转化统计和二分的对象来解决问题。
还有很多类似的思想:更换定义域和值域的权值线段树,通过离线来随意操纵时间线的 \(\text{cdq}\) 分治,通过倍增对值域进行划分的倍增分块等等,它们无疑是人类智慧的结晶,化不可做为可做,化不可能为可能。
代码
注释超详细
#include <bits/stdc++.h>
using namespace std;
const int N=600100;//因为是环,要断环成链,所以开双倍
typedef long long ll;
int n,m,k,in1,idx;
int to[N],nxt[N],ans[N];//我们需要用邻接表来存储一个国家的某个空间站的下一个空间站,不能每次遍历轨道,不然会 T(时间复杂度不变,但常数会变大)
struct country{int head,id;ll need;}con[N],con2[N];//国家的结构体,另一个是用来暂时存储的,head 是该国家邻接表的表头,id是国家编号,need是所需的陨石数量
struct stone{int l,r;ll a;}sto[N];//陨石结构体,左右端点和陨石数量
void add(int u,int v){idx++;to[idx]=v;nxt[idx]=con[u].head;con[u].head=idx;}//邻接表加边
struct Tree_array{//选择树状数组来辅助陨石下落
ll a[N];
#define lowbit(x) ((x)&(-(x)))
void change(int x,ll k){for(;x<=(m<<1);x+=lowbit(x)) a[x]+=k;}
ll ask(int x){ll ans=0;for(;x;x-=lowbit(x)) ans+=a[x];return ans;}//树状数组常规操作,单点加,区间查询
}tree;
void solve(int l,int r,int x,int y){
if(l==r){//到达边界了!
for(int i=x;i<=y;i++)
ans[con[i].id]=l;//得到该区间的国家的答案
return ;//速润
}
int mid=(l+r)>>1,ll=0,rr=n;//mid是区间中点,ll,rr是辅助暂时存储国家的两个计数变量
for(int i=l;i<=mid;i++){
tree.change(sto[i].l,sto[i].a);
tree.change(sto[i].r+1,-sto[i].a);
}//通过差分操作让树状数组实现区间修改
for(int s=x;s<=y;s++){
long long sum=0;
for(int i=con[s].head;i&&sum<=con[s].need;i=nxt[i])
sum+=tree.ask(to[i]+m)+tree.ask(to[i]);//对于这个国家,统计信息(树状数组的区间查询变成了单点查询,又因为断环成链所以要查询两个部分)
if(sum>=con[s].need) con2[++ll]=con[s];//划分到左区间
else con2[++rr]=con[s],con2[rr].need-=sum;//划分到右区间,同时需要的陨石减去这一部分(这样才可以保证以后的递归过程中只需要降落子区间前半部分的陨石就可以统计答案)
}
for(int i=l;i<=mid;i++){
tree.change(sto[i].l,-sto[i].a);
tree.change(sto[i].r+1,sto[i].a);
}//把陨石送回去
for(int i=1;i<=ll;i++)
con[x+i-1]=con2[i];//copy一份
for(int i=n+1;i<=rr;i++)
con[x+ll+i-n-1]=con2[i];
solve(l,mid,x,x+ll-1);//递归左右子区间
solve(mid+1,r,y-rr+n+1,y);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d",&in1);
add(in1,i);//加边
}
for(int i=1;i<=n;i++){
scanf("%lld",&con[i].need);//读入国家信息
con[i].id=i;
}
scanf("%d",&k);
for(int i=1;i<=k;i++){
scanf("%d%d%d",&sto[i].l,&sto[i].r,&sto[i].a);
if(sto[i].r<sto[i].l) sto[i].r+=m;//更新左端点
}
solve(1,k+1,1,n);//右端点划分到k+1,方便判断无解
for(int i=1;i<=n;i++){
if(ans[i]==k+1) cout<<"NIE\n";
else cout<<ans[i]<<'\n';
}
return 0;
}
Meteors 题解的更多相关文章
- BZOJ2527 & 洛谷3527:[Poi2011]Meteors——题解
+++++++++++++++++++++++++++++++++++++++++++ +本文作者:luyouqi233. + +欢迎访问我的博客:http://www.cnblogs.com/luy ...
- [Poi2011]Meteors 题解
题目大意: 给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值. 思路: 整体二分(二分答案),对于每个 ...
- 一篇自己都看不懂的CDQ分治&整体二分学习笔记
作为一个永不咕咕咕的博主,我来更笔记辣qaq CDQ分治 CDQ分治的思想还是比较简单的.它的基本流程是: \(1.\)将所有修改操作和查询操作按照时间顺序并在一起,形成一段序列.显然,会影响查询操作 ...
- BZOJ2527: [Poi2011]Meteors
补一发题解.. 整体二分这个东西,一开始感觉复杂度不是很靠谱的样子 问了po姐姐,说套主定理硬干.. #include<bits/stdc++.h> #define ll long lon ...
- BZOJ 2527 Meteors | 整体二分
BZOJ 2527 Meteors 题意 一个圆环上有m个位置,编号为1~m,分别属于n个国家. 有k个时刻,每个时刻都会给圆环上的一个区间中每个位置的值加上一个数. 每个国家有一个目标,问对于每个国 ...
- POI2011题解
POI2011题解 2214先咕一会... [BZOJ2212][POI2011]Tree Rotations 线段树合并模板题. #include<cstdio> #include< ...
- 【BZOJ2527】[Poi2011]Meteors 整体二分
[BZOJ2527][Poi2011]Meteors Description Byteotian Interstellar Union (BIU) has recently discovered a ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
随机推荐
- 2021/1/10例会 academy of management journal 2014vol 57 No.2,484-514
这次的论文由于考试周的原因看的不是很细,但大概还是浏览过一遍了.然后这次我的拓展又神奇的匹配到了教授想让我们接下来想看的论文. perfect! 但不足的是,没有进行相关论文的检索,自己的拓展没有理论 ...
- 前端Vue自定义带历史记录的搜索框组件searchBar 支持搜索输入框清空 搜索历史存储记录清除
前端Vue自定义带历史记录的搜索框组件searchBar 支持搜索输入框清空 搜索历史存储记录清除,下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/p ...
- Android实时获取摄像头画面传输至PC端
前言 最近在做一个PC端小应用,需要获取摄像头画面,但是电脑摄像头像素太低,而且位置调整不方便,又不想为此单独买个摄像头.于是想起了之前淘汰掉的手机,成像质量还是杠杠的,能不能把手机摄像头连接到电脑上 ...
- 嵌入式低功耗WiFi设备保活功耗分析
(一)嵌入式低功耗设备介绍 在物联网(IoT)领域,设备可以使用以太网和无线网进行网络连接. 以太网: 网络稳定,带宽高,延迟低,但是以太网需要拉网布线,设备安装邻活便利性能差. 无线网络:安装位置灵 ...
- 【git】基于JGit通过ssh-url拉取指定commit-id的代码
实现 1️⃣ pom依赖: <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>o ...
- 前后端分离实现注册+登录(Vue3.0 + Django3.2)
博客地址:https://www.cnblogs.com/zylyehuo/ 一.使用 vite+webstorm 搭建 Vue 环境,构建前端 1.结构树 2.main.js import { cr ...
- Centos7中Oracle占用CPU过高(解决方案)
Centos7中Oracle占用CPU过高(解决方案) 前言: 99%的问题几乎都是SQL的问题,一般SQL可能会出现以下几种情况: 相关SQL搜索条件没有加索引 索引失效 联合查询过多 数据量过大 ...
- pycharm:插件translation 更新TTK失败
解决方案 1.修改C:\Windows\System32\drivers\etc 下hosts文件, 添加 203.208.40.66 translate.google.com 203.208.40. ...
- AWVS14破解docker一键安装
先上个图 2021最新版 1.使用docker查看是否有awvs: [root@hadoop-01 awvs13-linux]# docker search awvs NAME ...
- .net开发-心情与效率
随着现代科技的不断发展,笔记本电脑已经成为我们日常生活中不可或缺的一部分.然而,在使用笔记本电脑的过程中,我们可能会遇到一些问题,例如显示器闪烁.HDMI接口接触不良等,这些问题不仅会影响我们的工作效 ...