[BalticOI 2017] Toll
做法很多,本人使用线段树。
原图可以看作分层 DAG,每层结点有 \(k\) 个,而 \(k\le 5\)。
假设每层的点编号 \(0\sim k-1\)。从 \(l\) 到 \(r\) 层的路径,在线段树上用区间 \([l,r-1]\) 表示。线段树上每个结点都存储表示最段路的矩阵,合并时使用 Floyd。
另外,需要特判询问中是否两个点在同一层里,这样一定不连通。
// Title: Toll // Source: P6573 // Author: Jerrywang #include <bits/stdc++.h> #define F first #define S second #define pii pair<int, int> #define ll long long #define rep(i, s, t) for(int i=s; i<=t; ++i) #define debug(x) cout<<#x<<":"<<x<<endl; const int N=50010, M=5; using namespace std; int k, n, m, T; vector<pii> g[N][M]; struct node { int l, r, d[M][M]; void clr() {memset(d, 0x3f, sizeof d);} } t[N<<2]; #define lc p<<1 #define rc p<<1|1 void up(node &a, node l, node r) { a.clr(); rep(w, 0, k-1) rep(u, 0, k-1) rep(v, 0, k-1) a.d[u][v]=min(a.d[u][v], l.d[u][w]+r.d[w][v]); } void build(int p, int l, int r) { t[p]={l, r}; if(l==r) { t[p].clr(); rep(u, 0, k-1) for(auto [v,w]:g[l][u]) t[p].d[u][v]=w; return; } int m=l+r>>1; build(lc, l, m), build(rc, m+1, r); up(t[p], t[lc], t[rc]); } node query(int p, int l, int r) { if(l<=t[p].l && t[p].r<=r) return t[p]; int m=t[p].l+t[p].r>>1; node res; if(r<=m) return query(lc, l, r); if(l>m) return query(rc, l, r); up(res, query(lc, l, r), query(rc, l, r)); return res; } int main() { #ifdef Jerrywang freopen("E:/OI/in.txt", "r", stdin); #endif scanf("%d%d%d%d", &k, &n, &m, &T); rep(i, 1, m) { int u, v, w; scanf("%d%d%d", &u, &v, &w); g[u/k][u%k].push_back({v%k, w}); } build(1, 0, n); while(T--) { int u, v; scanf("%d%d", &u, &v); int lu=u/k, lv=v/k; if(lu==lv) {puts("-1"); continue;} node t=query(1, lu, lv-1); int res=t.d[u%k][v%k]; printf("%d\n", res==0x3f3f3f3f?-1:res); } return 0; }
本文作者:JosephusWang
本文链接:https://www.cnblogs.com/JosephusWang/p/18064346
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
杂题题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步