洛谷 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 ...
随机推荐
- 解决Mybatis 报错Invalid bound statement (not found)
解决Mybatis 报错Invalid bound statement (not found) 出现此错误的原因 1.xml文件不存在 2.xml文件和mapper没有映射上 namespace指定映 ...
- 机器学习:KNN
KNN:K-nearst neighbors 简介: k-近邻算法采用测量不同特征值之间的距离来进行分类,简而言之为:人以类聚,物以群分 KNN既可以应用于分类中,也可用于回归中:在分类的预测是,一般 ...
- stm32学习心得体会
stm32作为现在嵌入式物联网单片机行业中经常要用多的技术,相信大家都有所接触,今天这篇就给大家详细的分析下有关于stm32的出口,还不是很清楚的朋友要注意看看了哦,在最后还会为大家分享有些关于stm ...
- mybatis竟然报"Invalid value for getInt()"
目录 背景 场景 初探 再探 结局 背景 使用mybatis遇到一个非常奇葩的问题,错误如下: Cause: org.apache.ibatis.executor.result.ResultMapEx ...
- (类)Program1.1
1 class MyClass: 2 3 i = 12345 4 5 def __init__(self): 6 self.data = "WOOWOWOWO" 7 8 def f ...
- P2120 [ZJOI2007]仓库建设
P2120 [ZJOI2007]仓库建设 怎么说呢?算是很水的题了吧... 只要不要一开始就把dp想错就行... #include<bits/stdc++.h> #define ll lo ...
- cf14C Four Segments(计算几何)
题意: 给四个线段(两个端点的坐标). 判断这四个线段能否构成一个矩形.(矩形的四条边都平行于X轴或Y轴) 思路: 计算几何 代码: class Point{ public: int x,y; voi ...
- 数组模拟双链表,你get到了吗?
数组模拟双链表 通过前面的学习我们知道单链表是单个指针指向操作,那么通过类比我们可以把指针设定为两个,并且让它们分别指向前后数据,这就是"双向链表".使用这种链表,不仅可以从前往后 ...
- CDP客户数据管理平台体系化搭建
一.Cdp系统简介 1.基本概念 客户数据平台(Customer-Data-Platform),简称CDP:通过采集多方客户数据(主体与线索)等,从而进行精准的客户分析和人群细分,进而实现高效的客户维 ...
- 聊了聊宏内核和微内核,并吹了一波 Linux
看这里!!!https://mp.weixin.qq.com/s?__biz=MzI0ODk2NDIyMQ==&mid=2247494048&idx=1&sn=cacfc6a4 ...