1~8号测试点,32分做法
\qquad 暴力加边,跑 D i j s t r a Dijstra Dijstra
9~13号测试点 20分做法
\qquad 加边的时候二分或直接把点存进一个 m a p map map,暴力跑 D i j s t r a Dijstra Dijstra
14~18号测试点 20分做法
\qquad 出门左转线段树优化建图模板题
或许是实现起来最简单还不用卡常的100分做法:线段树套 s e t set set \qquad 首先这题需要发现2个很有用的性质:
- 性质 1 1 1,用 D i j s t r a Dijstra Dijstra跑最短路时,对于每个点,都只会在堆中弹出1次
- 【洛谷P5471 NOI2019弹跳】性质 2 2 2,对于每个弹跳装置,通过这一个弹跳装置到达的矩形中所有城市需要的时间相同(不是矩形中每个城市的最短路相同,而是通过这个装置到达它们的时间相同)
找到特定矩形中任意一个没有出现过的城市,跑最短路 \qquad 至于为什么只取矩形中的一个点,因为本蒟蒻太菜了,感觉不好操作,也只是常数问题。
\qquad 那么这题就被我们转换成了一道支持插入、删除任意一点、在某特定范围中查找第一个点的的二维数据结构+ D i j s t r a Dijstra Dijstra的题目。
\qquad 因为我们需要找到第一个未出现过的城市的确切位置,那么明显需要二分,所以外面就选择线段树。里面的比较随意,支持删除、可以动态开空间就行。而这题卡空间,不能用二维线段树,于是我们可以选择线段树套平衡树,为了方便,直接上 s e t set set。
时空复杂度分析 \qquad 因为小蒟蒻的写法很不优秀,可能要查询(m+n)次,线段树查询最多 l o g log log个区间,每个区间用set查询,时间复杂度 O ( ( m + n ) l o g 2 2 n ) O((m+n)log_2^2n) O((m+n)log22?n)。插入城市时,深度为 l o g ( n ) log(n) log(n),往线段树插入n个城市,所以空间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
丑陋的代码:
// luogu-judger-enable-o2
#include
using namespace std;
inline int read(){
int a=0;
char c=getchar();
while(c>57 or c<48)c=getchar();
while(47b.t;
}
};
//矩阵的结构体,记录时间和大小
vectoredge[MN];
//记录每个城市的弹跳装置指向的矩形
priority_queueQ;
//优先队列
void Insert(int x,int l,int r,int loc,int id,int y){
//x坐标和线段树的编号重了,改成了loc
int mid=(l+r)>>1;
num[x].insert(P(id,loc,y));
sum[x]++;
if(l==r)return;
if(mid>=loc)Insert(Ls,l,mid,loc,id,y);
else Insert(Rs,mid+1,r,loc,id,y);
}//在线段树中插入城市
void del(int x,int l,int r,int loc,int id,int y){
int mid=(l+r)>>1;
num[x].erase(num[x].find(P(id,loc,y)));
sum[x]--;
if(l==r)return;
if(mid>=loc)del(Ls,l,mid,loc,id,y);
else del(Rs,mid+1,r,loc,id,y);
}//在线段树中删除城市
int ask(int x,int l,int r,int b,int e,int L,int R){
if(!sum[x]||l>e||rR||y[tmp]>1;
int tmp=ask(Ls,l,mid,b,e,L,R);
if(tmp) return tmp;
return ask(Rs,mid+1,r,b,e,L,R);
}//找出区间中第一个点
void Dij(){
while(!Q.empty())Q.pop();
for(int i=1;
i<=n;
++i)f[i]=INF;
f[1]=0;
Q.push(Mat(0,x[1],x[1],y[1],y[1]));
while(!Q.empty()){
Mat w=Q.top();
int cur=ask(1,1,W,w.l,w.r,w.d,w.u);
if(!cur){Q.pop();
continue;
}//一个矩形里没有城市时再删除
del(1,1,W,x[cur],cur,y[cur]);
f[cur]=w.t;
cnt++;
if(cnt==n)break;
//松弛完直接break,因为后面的查询也需要log^2的时间但是肯定不会对结果造成影响
for(int i=0;
i
推荐阅读
- 题解|【HNOI2017】大佬-dalao
- 2019 GDUT Rating Contest #II 这是群题解,七篇!!!
- # 2019 GDUT Rating Contest #I H. Mixing Milk
- # 2019 GDUT Rating Contest #I A. The Bucket List
- # 2019 GDUT Rating Contest #I G. Back and Forth
- 2019 GDUT Winter Personal Training Contest III (Div. 2) A题 QAQ 题解
- 2019 GDUT Winter Personal Training Contest I (Div. 2) A. Protect Sheep
- 题解|题解 | K-ary Heap-2019牛客暑期多校训练营第六场F题
- ACM|[dsu] codeforces 375D. Tree and Queries
- 题解|[BZOJ3817] Sum