洛谷 P5471 - [NOI2019] 弹跳(二维线段树优化建图+堆优化存边)
一道非常有意思的题(大概可以这么形容?)
首先看到这类一个点想一个区域内连边的题目可以很自然地想到线段树优化建图,只不过这道题是二维的,因此需要使用二维线段树优化建图,具体来说,我们外层开一棵大线段树维护 \(x\) 轴下标区间,大线段树上每个节点又套了个小的动态开点线段树,每次我们从一个点向一个矩形连边时就在动态开点线段树上找到对应的区间并从这个点向这些区间中连边,不难发现这个做法点数是 \(\mathcal O(n\log^2n)\) 级别的,边数是 \(\mathcal O(m\log^2n)\) 级别的,总复杂度 \(m\log^3n\),然鹅梦想很美满,现实很骨感,这个做法,它,MLE 了!因此我们还得考虑别的做法。
这时候就要用到一个叫做”堆优化存边“的 trick 了,在正常的 dijkstra 求最短路的过程中,我们小根堆中存的是起点到每个点的距离与其形成的 pair,但是这次咱们偏不存点,咱们存边,也就是题目中所说的弹跳装置。显然对于一个弹跳装置而言,如果起点到它的出发点 \(p_i\) 的最短路径长度已知,那么它用来更新矩形中所有点的距离就已经知道了——是 \(dis_{p_i}+t_i\),那么我们就将 \(dis_{p_i}+t_i\) 与弹跳装置的编号 \(i\) 看作一个 pair 压入小根堆中,每次取出小根堆的最小节点并找到它对应弹跳装置中的所有节点集合 \(S\)——这个咱们可以用线段树套 set 来求出,然后直接令 \(S\) 当中的点的最短路径为 \(dis_{p_i}+t_i\),然后将这些点直接从线段树中删除,显然每个点最多被访问并删除一次,每个点最多在 \(\log n\) 个节点中出现,再加上 set 的复杂度,总复杂度俩 \(\log\)。而且由于我们每次取出的是贡献最小的弹跳装置,因此每次找出的 \(S\) 中的节点必然是无法被更小的弹跳装置更新的,因此求出来的距离必定是起点到每个点的最短路。这样时间复杂度 \(n\log^2n+m\),空间复杂度 \(n\log n+m\),就不用再担心空间的问题了。
const int MAXN=7e4;
const int MAXM=1.5e5;
int n,m,w,h,dis[MAXN+5];
struct city{
int x,y,id;
city(int _x=0,int _y=0,int _id=0):x(_x),y(_y),id(_id){}
bool operator <(const city &rhs) const{
return (y^rhs.y)?(y<rhs.y):(id<rhs.id);
}
} a[MAXN+5];
priority_queue<pii,vector<pii>,greater<pii> > q;
set<city> st[MAXN*4+5];
vector<int> fr[MAXN+5];
struct bar{int p,l,r,u,d,c;} b[MAXM+5];
void insert(int k,int l,int r,int v){
st[k].insert(a[v]);if(l==r) return;int mid=l+r>>1;
(a[v].x<=mid)?insert(k<<1,l,mid,v):insert(k<<1|1,mid+1,r,v);
}
void del(int k,int l,int r,int v){
st[k].erase(st[k].find(a[v]));if(l==r) return;int mid=l+r>>1;
(a[v].x<=mid)?del(k<<1,l,mid,v):del(k<<1|1,mid+1,r,v);
}
void update(int k,int l,int r,int x,int y){
if(b[x].l<=l&&r<=b[x].r){
while(1){
set<city>::iterator it=st[k].lower_bound(city(0,b[x].d,0));
if(it==st[k].end()||(it->y)>b[x].u) break;
int id=(it->id);dis[id]=y;
for(int t:fr[id]) q.push(mp(y+b[t].c,t));
del(1,1,w,id);
} return;
} int mid=l+r>>1;
if(b[x].r<=mid) update(k<<1,l,mid,x,y);
else if(b[x].l>mid) update(k<<1|1,mid+1,r,x,y);
else update(k<<1,l,mid,x,y),update(k<<1|1,mid+1,r,x,y);
}
int main(){
scanf("%d%d%d%d",&n,&m,&w,&h);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y),a[i].id=i,insert(1,1,w,i);
for(int i=1;i<=m;i++){
scanf("%d%d%d%d%d%d",&b[i].p,&b[i].c,&b[i].l,&b[i].r,&b[i].d,&b[i].u);
fr[b[i].p].pb(i);
} b[++m].c=0;b[m].l=b[m].r=a[1].x;b[m].u=b[m].d=a[1].y;q.push(mp(0,m));
while(!q.empty()){pii p=q.top();q.pop();/*printf("%d %d\n",p.fi,p.se);*/update(1,1,w,p.se,p.fi);}
for(int i=2;i<=n;i++) printf("%d\n",dis[i]);
return 0;
}
洛谷 P5471 - [NOI2019] 弹跳(二维线段树优化建图+堆优化存边)的更多相关文章
- 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra
题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...
- 洛谷.3437.[POI2006]TET-Tetris 3D(二维线段树)
题目链接 下落一个d*s的方块,则要在这个平面区域找一个最高的h' 更新整个平面区域的值为h+h' 对于本题,维护最大高度h和all 对于平面的x轴维护一棵线段树t1,每个t1的节点维护对应y轴的两棵 ...
- 洛谷P3437 [POI2006]TET-Tetris 3D(二维线段树 标记永久化)
题意 题目链接 Sol 二维线段树空间复杂度是多少啊qwqqq 为啥这题全网空间都是\(n^2\)还有人硬要说是\(nlog^2n\)呀.. 对于这题来说,因为有修改操作,我们需要在外层线段树上也打标 ...
- 洛谷 P3688 - [ZJOI2017]树状数组(二维线段树+标记永久化)
题面传送门 首先学过树状数组的应该都知道,将树状数组方向写反等价于前缀和 \(\to\) 后缀和,因此题目中伪代码的区间求和实质上是 \(sum[l-1...n]-sum[r...n]=sum[l-1 ...
- 洛谷 P3397 地毯 【二维差分标记】
题目背景 此题约为NOIP提高组Day2T1难度. 题目描述 在n*n的格子上有m个地毯. 给出这些地毯的信息,问每个点被多少个地毯覆盖. 输入输出格式 输入格式: 第一行,两个正整数n.m.意义如题 ...
- BZOJ.4553.[HEOI2016&TJOI2016]序列(DP 树状数组套线段树/二维线段树(MLE) 动态开点)
题目链接:BZOJ 洛谷 \(O(n^2)\)DP很好写,对于当前的i从之前满足条件的j中选一个最大值,\(dp[i]=d[j]+1\) for(int j=1; j<i; ++j) if(a[ ...
- Codeforces 453E - Little Pony and Lord Tirek(二维线段树+ODT)
Codeforces 题目传送门 & 洛谷题目传送门 一道难度 *3100 的 DS,而且被我自己搞出来了! 不过我终究还是技不如人,因为这是一个 \(n\log^2n\) + 大常数的辣鸡做 ...
- UVA 11297 线段树套线段树(二维线段树)
题目大意: 就是在二维的空间内进行单个的修改,或者进行整块矩形区域的最大最小值查询 二维线段树树,要注意的是第一维上不是叶子形成的第二维线段树和叶子形成的第二维线段树要 不同的处理方式,非叶子形成的 ...
- POJ2155 Matrix二维线段树经典题
题目链接 二维树状数组 #include<iostream> #include<math.h> #include<algorithm> #include<st ...
随机推荐
- 笨方法学python中执行argv提示ValueError: not enough values to unpack (expected 4, got 1)
解决方法:选择Terminal中输入执行ex13.py 1 2 3 执行结果如下图
- pycharm安装第三方库
https://jingyan.baidu.com/article/4853e1e54b845e1909f7268f.html
- python的虚拟环境Anaconda使用
Anaconda 使用conda常用命令 1.首先在所在系统中安装Anaconda.可以打开命令行输入conda -V检验是否安装以及当前conda的版本. 2.conda常用的命令. 1)con ...
- BUAA2020软工团队beta得分总表
BUAA2020软工团队beta得分总表 [TOC] 零.团队博客目录及beta阶段各部分博客地址 团队博客 计划与设计博客 测试报告博客 发布声明博客 事后分析博客 敏 杰 开 发♂ https:/ ...
- 【二食堂】Beta - 测试报告
Beta - 测试报告 测试过程中发现的bug Beta阶段的新bug 我们在Beta阶段的开发过程中就进行了测试,发现了许多bug.这其中后端的bug比较多,在这里我列举一些比较重要的功能性bug. ...
- 【二食堂】Alpha - Scrum Meeting 6
Scrum Meeting 6 例会时间:4.16 11:40 - 12:10 进度情况 组员 昨日进度 今日任务 李健 1. 文本区域进度40%,UI需要进行调整issue 1. 继续文本区域的开发 ...
- OO_JAVA_JML系列第三次作业__架构之谈
OO_JAVA_JML系列第三次作业 ## ----架构之谈 目录 OO_JAVA_JML系列第三次作业 出发点 操作的可分离性 操作本身的多样性 实现手段:表驱动编程 储存 注册 出发点 操作的可分 ...
- dwr简单应用及一个反向ajax消息推送
由于项目中最近需要用到dwr实现一些功能,因此在网上和dwr官网上找了一些资料进行学习.在此记录一下.(此处实现简单的dwr应用和dwr消息反向推送) 一.引入dwr的包 <dependency ...
- 问题:两个对象值相同(x.equals(y) == true),但是可能存在hashCode不同吗?
面试官的考察点 这道题仍然是考察JVM层面的基本知识,面试官认为,基本功扎实,才能写出健壮性和稳定性很高的代码. 涉及到的技术知识 (x.equals(y)==true),这段代码,看起来非常简单,但 ...
- NKOJ-2936 城市建设
问题描述: PS国是一个拥有诸多城市的大国,国王Louis为城市的交通建设可谓绞尽脑汁.Louis可以在某些城市之间修建道路,在不同的城市之间修建道路需要不同的花费.Louis希望建造最少的道路使得国 ...