卧薪尝胆,厚积薄发。
AMPPZ2014 Petrol
Date: Sat Dec 22 08:50:02 CST 2018
In Category:
NoCategory
Description:
$n$
个点
$m$
条边的带权无向图,
$s$
个点是加油站。
$q$
次询问出发点是
$x$
,终点是
$y$
,油量上限为
$b$
,保证
$x$
和
$y$
都是加油站,请回答能否从
$x$
走到
$y$
。
$1\leqslant n\leqslant 2\times 10^5$
Solution:
发现实际上只有加油站这些关键点之间的距离是有用的,于是先跑一遍多源
$dijkstra$
预处理出每个点最近的加油站和到它的距离,然后连边
$(c[x],c[y],d[x]+d[y]+v(x,y))$
,然后求出关键点之间的最小生成树,然后就可以倍增求链上最小值了。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
int n,s,m,p;
#define MAXN 200010
int c[MAXN];
struct edge
{
int to,nxt,v;
}e[MAXN << 1];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b,int c)
{
e[++edgenum] = (edge){b,lin[a],c};lin[a] = edgenum;
e[++edgenum] = (edge){a,lin[b],c};lin[b] = edgenum;
return;
}
int d[MAXN],pos[MAXN];
bool vis[MAXN];
struct edges
{
int u,v,w;
}es[MAXN];
int edgesnum = 0;
void addedges(int a,int b,int c)
{
es[++edgesnum] = (edges){a,b,c};
return;
}
int f[MAXN];
int find(int x){return (x == f[x] ? x : f[x] = find(f[x]));}
bool cmp_w(edges a,edges b){return a.w < b.w;}
int g[MAXN][18],h[MAXN][18];
int dep[MAXN];
int ins[MAXN],scc = 0;
void dfs(int k,int depth)
{
ins[k] = scc;
dep[k] = depth;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(e[i].to == h[k][0])continue;
h[e[i].to][0] = k;
g[e[i].to][0] = e[i].v;
dfs(e[i].to,depth + 1);
}
return;
}
int query(int a,int b)
{
int res = 0;
if(dep[a] < dep[b])swap(a,b);
for(int k = 17;k >= 0;--k)
{
if(dep[h[a][k]] >= dep[b])
{
res = max(res,g[a][k]);
a = h[a][k];
}
}
if(a == b)return res;
for(int k = 17;k >= 0;--k)
{
if(h[a][k] != h[b][k])
{
res = max(res,max(g[a][k],g[b][k]));
a = h[a][k];b = h[b][k];
}
}
res = max(res,max(g[a][0],g[b][0]));
return res;
}
int main()
{
scanf("%d%d%d",&n,&s,&m);
for(int i = 1;i <= s;++i)scanf("%d",&c[i]);
int a,b,v;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&a,&b,&v);
add(a,b,v);
}
priority_queue< pair<int,int> > q;
memset(d,0x3f,sizeof(d));
for(int i = 1;i <= s;++i)
{
q.push(make_pair(0,c[i]));
d[c[i]] = 0;pos[c[i]] = c[i];
}
while(!q.empty())
{
int k = q.top().second;q.pop();
if(vis[k])continue;
vis[k] = true;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(d[e[i].to] > d[k] + e[i].v)
{
d[e[i].to] = d[k] + e[i].v;
pos[e[i].to] = pos[k];
q.push(make_pair(-d[e[i].to],e[i].to));
}
}
}
for(int i = 1;i <= edgenum;i += 2)
{
addedges(pos[e[i].to],pos[e[i + 1].to],d[e[i].to] + d[e[i + 1].to] + e[i].v);
}
sort(es + 1,es + 1 + m,cmp_w);
edgenum = 0;
memset(lin,0,sizeof(lin));
for(int i = 1;i <= n;++i)f[i] = i;
for(int i = 1;i <= m;++i)
{
int p = find(es[i].u),q = find(es[i].v);
if(p == q)continue;
f[p] = q;
add(p,q,es[i].w);
}
memset(vis,false,sizeof(vis));
for(int i = 1;i <= s;++i)
{
if(ins[c[i]] == 0)
{
++scc;
dfs(c[i],1);
}
}
for(int k = 1;k <= 17;++k)
{
for(int i = 1;i <= s;++i)
{
int p = c[i];
h[p][k] = h[h[p][k - 1]][k - 1];
g[p][k] = max(g[p][k - 1],g[h[p][k - 1]][k - 1]);
}
}
scanf("%d",&p);
for(int i = 1;i <= p;++i)
{
scanf("%d%d%d",&a,&b,&v);
if(ins[a] != ins[b])puts("NIE");
else if(query(a,b) <= v)puts("TAK");
else puts("NIE");
}
return 0;
}
In tag:
图论-dijkstra 图论-kruskal
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡