生活随笔
收集整理的這篇文章主要介紹了
【NOI2019】弹跳【二维线段树】【dijkstra】
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
題意:一個w×hw\times hw×h的二維平面上有nnn個城市,有mmm個彈跳裝置,第iii個可以花費tit_iti?的時間從城市pip_ipi?跳到矩形x∈[l,r],y∈[u,d]x\in [l,r],y\in[u,d]x∈[l,r],y∈[u,d]中的任意一個城市。求從111到其他每個城市的最小時間。
w,h≤n≤7×104,m≤1.5×105w,h\leq n\leq7\times 10^4,m\leq1.5\times10^5w,h≤n≤7×104,m≤1.5×105 空間限制128M
考慮直接套dijkstra的思路,每次選出dis最小的點,松弛它可以到的點,然后把它刪掉。
挪到二維平面上,你需要支持:
全局詢問最小值矩形取min?\minmin刪除一個點
用kdt或者二維線段樹維護即可。這里用的是二維線段樹。
需要注意的細(xì)節(jié):
要動態(tài)開點要用pair記錄最小值的編號,且初值是(INF,INF),否則可能打了個lazy標(biāo)記之后first是答案標(biāo)號卻是0。大常數(shù)選手需要維護一個最大值剪枝。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#include <utility>
#define re register
#define MAXN 70005
using namespace std
;
const int INF
=0x7fffffff;
inline int read()
{int ans
=0;char c
=getchar();while (!isdigit(c
)) c
=getchar();while (isdigit(c
)) ans
=(ans
<<3)+(ans
<<1)+(c
^48),c
=getchar();return ans
;
}
typedef pair
<int,int> pi
;
#define mp make_pair
#define fi first
#define se second
struct tran
{int xl
,xr
,yl
,yr
;tran(int xl
=0,int xr
=0,int yl
=0,int yr
=0):xl(xl
),xr(xr
),yl(yl
),yr(yr
){}};
inline bool belong(const tran
& b
,const tran
& a
){return a
.xl
<=b
.xl
&&b
.xr
<=a
.xr
&&a
.yl
<=b
.yl
&&b
.yr
<=a
.yr
;}
inline bool ninter(const tran
& a
,const tran
& b
){return (a
.xr
<b
.xl
||b
.xr
<a
.xl
)||(a
.yr
<b
.yl
||b
.yr
<a
.yl
);}
struct edge
{tran t
;int w
;};
vector
<edge
> e
[MAXN
];
#define ch(x) t[p].son[x]
int tot
=0,rt
;
struct node
{tran pos
;pi mn
;int mx
,sum
,lzy
,son
[4];}t
[MAXN
<<5];
inline int newnode(int xl
,int xr
,int yl
,int yr
)
{int p
=++tot
;t
[p
].pos
=tran(xl
,xr
,yl
,yr
);t
[p
].mn
=mp(INF
,INF
);t
[p
].mx
=0;t
[p
].lzy
=INF
;return p
;
}
inline void update(int p
)
{t
[p
].sum
=t
[ch(0)].sum
+t
[ch(1)].sum
+t
[ch(2)].sum
+t
[ch(3)].sum
;t
[p
].mn
=mp(INF
,INF
),t
[p
].mx
=0;for (re
int i
=0;i
<4;++i
) if (ch(i
)) t
[p
].mn
=min(t
[p
].mn
,t
[ch(i
)].mn
),t
[p
].mx
=max(t
[p
].mx
,t
[ch(i
)].mx
);
}
inline void pushlzy(int p
,int v
)
{if (t
[p
].sum
==0) return;t
[p
].mn
.fi
=min(t
[p
].mn
.fi
,v
),t
[p
].mx
=min(t
[p
].mx
,v
),t
[p
].lzy
=min(t
[p
].lzy
,v
);
}
inline void pushdown(int p
)
{if (t
[p
].lzy
<INF
){for (re
int i
=0;i
<4;++i
) pushlzy(ch(i
),t
[p
].lzy
);t
[p
].lzy
=INF
;}
}
void modify(int& p
,int xl
,int xr
,int yl
,int yr
,int x
,int y
,int v
)
{if (!p
) p
=newnode(xl
,xr
,yl
,yr
);if (!belong(tran(x
,x
,y
,y
),t
[p
].pos
)) return;pushdown(p
);if (t
[p
].pos
.xl
==t
[p
].pos
.xr
&&t
[p
].pos
.yl
==t
[p
].pos
.yr
) return (void)(t
[p
].sum
=(v
<INF
),t
[p
].mn
=mp(INF
,v
),t
[p
].mx
=(v
==INF
? 0:INF
));int xmid
=(xl
+xr
)>>1,ymid
=(yl
+yr
)>>1; modify(ch(0),xl
,xmid
,yl
,ymid
,x
,y
,v
);modify(ch(1),xl
,xmid
,ymid
+1,yr
,x
,y
,v
);modify(ch(2),xmid
+1,xr
,yl
,ymid
,x
,y
,v
);modify(ch(3),xmid
+1,xr
,ymid
+1,yr
,x
,y
,v
); update(p
);
}
void modify(int p
,tran q
,int v
)
{if (!p
) return;pushdown(p
); if (t
[p
].mx
<=v
) return;if (belong(t
[p
].pos
,q
)) return pushlzy(p
,v
);if (ninter(t
[p
].pos
,q
)) return;for (int i
=0;i
<4;i
++) modify(ch(i
),q
,v
);update(p
);
}
int x
[MAXN
],y
[MAXN
],ans
[MAXN
];
int main()
{int n
,m
,w
,h
;n
=read(),m
=read(),w
=read(),h
=read();for (int i
=1;i
<=n
;i
++){x
[i
]=read(),y
[i
]=read();modify(rt
,1,w
,1,h
,x
[i
],y
[i
],i
);}for (int i
=1;i
<=m
;i
++){int p
,t
,l
,r
,d
,u
;p
=read(),t
=read(),l
=read(),r
=read(),d
=read(),u
=read();e
[p
].push_back((edge
){tran(l
,r
,d
,u
),t
});}modify(1,tran(x
[1],x
[1],y
[1],y
[1]),0);for (int T
=1;T
<=n
;T
++){pi tmp
=t
[1].mn
;int u
=tmp
.se
,dis
=tmp
.fi
;ans
[u
]=dis
;for (int i
=0;i
<(int)e
[u
].size();i
++)modify(1,e
[u
][i
].t
,dis
+e
[u
][i
].w
);modify(rt
,1,w
,1,h
,x
[u
],y
[u
],INF
);}for (int i
=2;i
<=n
;i
++) printf("%d\n",ans
[i
]);return 0;
}
總結(jié)
以上是生活随笔為你收集整理的【NOI2019】弹跳【二维线段树】【dijkstra】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。