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 ...
随机推荐
- Dlang 并行化
Dlang 并行化 好难受,dlang 生态太差,没办法,学了半天才明白. 我尽量以精炼的语言解释. 采用 定义,例子(代码),解释 的步骤讲解. 所以你可能看到很多代码,一点解释-- 我会省略一些 ...
- 端口探测神器——Nmap
Nmap 简介: 全称网络映射器,能快速扫描大型网络或单个网络上有哪些主机,这些主机提供什么服务,可以发现服务器运行在什么操作系统上,从而发现可攻击的脆弱点,扩大攻击范围 Nmap有图形化版本名叫Ze ...
- 基于DirectX11+ImGui的Win32桌面程序开发
一.常见图形界面框架(DirectUI.GUI) 1.题外话,纯属扯O 举两个常用的开发框架,MFC和Qt Widget里面每个控件都是Window,这是和DirectUI最大的区别.下面简单梳理下这 ...
- Flutter upgrade 卡死问题
使用 到本地的flutter sdk的目录下 $flutter upgrade --force 降低到指定版本 : $flutter version 1.22.4
- 全网最详细4W字Flink入门笔记(下)
本文已收录至Github,推荐阅读 Java随想录 微信公众号:Java随想录 目录 Flink State状态 CheckPoint & SavePoint CheckPoint原理 Sav ...
- 我开源了团队内部基于SpringBoot Web快速开发的API脚手架v1.6.0更新
什么是 rest-api-spring-boot-starter rest-api-spring-boot-starter 适用于SpringBoot Web API 快速构建让开发人员快速构建统一规 ...
- [gin]数据解析和绑定
前言 go version: 1.18 本文主要包含JSON.Form.Uri.XML的数据解析与绑定. JSON数据解析与绑定 go代码 package main import ( "ne ...
- SQL 注入学习手册【笔记】
SQL 注入基础 [若本文有问题请指正] 有回显 回显正常 基本步骤 1. 判断注入类型 数字型 or 字符型 数字型[示例]:?id=1 字符型[示例]:?id=1' 这也是在尝试闭合原来的 sql ...
- 十年磨一剑的华为云GES,高明在哪
本文分享自华为云社区<华为云GES:十年磨一剑,打造业界一流的云原生分布式图数据库>,作者:GES图引擎服务小图 . 1.浅谈云原生图数据库 图数据库(graph database)是一个 ...
- Airtest遇到模拟器无法输入中文的情况该如何处理?
此文章来源于项目官方公众号:"AirtestProject" 版权声明:允许转载,但转载必须保留原链接:请勿用作商业或者非法用途 1. 前言 最近有收到同学们的一些提问,使用Air ...