bzoj4144: [AMPPZ2014]Petrol 最短路经典问题

链接
Description
给定一个n个点、m条边的带权无向图,其中有s个点是加油站。
每辆车都有一个油量上限b,即每次行走距离不能超过b,但在加油站可以补满。
q次询问,每次给出x,y,b,表示出发点是x,终点是y,油量上限为b,且保证x点和y点都是加油站,请回答能否从x走到y。
Input
第一行包含三个正整数n,s,m(2<=s<=n<=200000,1<=m<=200000),表示点数、加油站数和边数。
第二行包含s个互不相同的正整数c[1],c[2],…cs,表示每个加油站。
接下来m行,每行三个正整数u[i],v[i],di,表示u[i]和v[i]之间有一条长度为d[i]的双向边。
接下来一行包含一个正整数q(1<=q<=200000),表示询问数。
接下来q行,每行包含三个正整数x[i],y[i],bi,表示一个询问。

题解:
我不在赘述,直接引用大佬的

积累的思想,以图中k个关键点两两距离的最小生成树问题,只需跑多源最短路,每个点记录它最近的关键点,在枚举边连边

最后判联通可以离线,直接按b排序+并查集,比lca好写。主要是代码量少些。
虽然我的代码20min能够写完,但是在比赛中写这么多代码精力消耗会比较大,并且细节容易错

调题时一定不要想当然,比如当时就认为点不连通可以直接判掉,其实没有,对拍才发现,早就应该发现的

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define repd(i,a,b) for(int i=a;i>=b;--i)
#define rvc(i,S) for(int i=0;i<(int)S.size();++i)
#define fore(i,x) for(int i = head[x] ; i ; i = e[i].next)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define lowbit(x) (x&(-x))
using namespace std;
#define maxn 200020
#define inf INT_MAX

struct node{
	int x,y,w;
	bool operator < (node a)const{
		return w < a.w;
	}
}E[maxn * 2];
struct node2{
	int next,to,w;
}e[maxn * 2],e2[maxn * 2];
int head[maxn],head2[maxn],cnt;
int fa[maxn],dis[maxn],q[maxn * 40],hh,tt,p[maxn],inq[maxn];
int n,m,T,s,tag[maxn],dth[maxn],jump[20][maxn],mx[20][maxn],tot,rt,vis[maxn],times;

inline void adde(int x,int y,int w){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	e[cnt].w = w;
	head[x] = cnt;
}
void spfa(){
	while ( hh < tt ){
		int x = q[hh++];
		inq[x] = 0;
		fore(i,x){
			if ( dis[e[i].to] > dis[x] + e[i].w ){
				dis[e[i].to] = dis[x] + e[i].w;
				p[e[i].to] = p[x];
				if ( !inq[e[i].to] ){
					q[tt++] = e[i].to;
					inq[e[i].to] = 1;
				}
			}
		}
	}
}
inline void adde2(int x,int y,int w);
int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }
void kruskal(){
	rep(x,1,n){
		fore(i,x){
			if ( p[x] != p[e[i].to] )
			   	E[++tot] = (node){p[x],p[e[i].to],dis[x] + dis[e[i].to] + e[i].w};
		}
	}
	sort(E + 1,E + tot + 1);
	rep(i,1,n) fa[i] = i;
	cnt = 0;
	rep(i,1,tot){
		int x = E[i].x , y = E[i].y ,w = E[i].w;
		int p = getfa(x) , q = getfa(y);
		if ( p != q ){
			fa[p] = q;
	//		cout<<x<<" "<<y<<" "<<w<<endl;
			adde2(x,y,w) , adde2(y,x,w);
		}
	}
}
#define e e2
#define head head2

inline void adde2(int x,int y,int w){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	e[cnt].w = w;
	head[x] = cnt;
}
void dfs(int x){
	vis[x] = times;
	for(int i = head[x] ; i ; i = e[i].next){
		if ( e[i].to == fa[x] ) continue;
		fa[e[i].to] = jump[0][e[i].to] = x;
		mx[0][e[i].to] = e[i].w;
		dth[e[i].to] = dth[x] + 1;
		dfs(e[i].to);
	}
}
void init(){
	rep(i,1,19)
		rep(j,1,n){
			jump[i][j] = jump[i - 1][jump[i - 1][j]];
			mx[i][j] = max(mx[i - 1][j],mx[i - 1][jump[i - 1][j]]);
		}
}
#undef e
#undef head

inline int getmx(int x,int y){
	if ( dth[x] < dth[y] ) swap(x,y);
	int d = dth[x] - dth[y],res = 0;
	
	rep(i,0,19) if ( d & (1 << i) ) res = max(res,mx[i][x]) , x = jump[i][x];
	if ( x == y ) return res;
	repd(i,19,0) if ( jump[i][x] != jump[i][y] ){
		res = max(res,max(mx[i][x],mx[i][y]));
		x = jump[i][x], y = jump[i][y];
	}
	res = max(res,max(mx[0][x],mx[0][y]));
	return res;
}
inline bool check(int x,int y,int b){
	return getmx(x,y) <= b;
}
int main(){
	freopen("input.txt","r",stdin);
	scanf("%d %d %d",&n,&s,&m);
	rep(i,1,n) dis[i] = inf;
	rep(i,1,s){
 	int x;
		scanf("%d",&x);
		q[tt++] = x , dis[x] = 0 , p[x] = x , inq[x] = 1 , tag[x] = 1;
	}
	rep(i,1,m){
		int x,y,w;
		scanf("%d %d %d",&x,&y,&w);
		adde(x,y,w) , adde(y,x,w);
	}
	spfa();
//	rep(i,1,n) cout<<p[i]<<" "<<dis[i]<<endl;
	kruskal();
	rep(i,1,n) fa[i] = 0;
	rep(i,1,n) if ( tag[i] && !fa[i] ){ ++times , dfs(i); }
	init();
	scanf("%d",&T);
	while ( T-- ){
		int x,y,b;
		scanf("%d %d %d",&x,&y,&b);
		if ( vis[x] == vis[y] && check(x,y,b) ) printf("TAK\n");
		else printf("NIE\n");
	}
}


猜你喜欢

转载自blog.csdn.net/weixin_42484877/article/details/83421425
今日推荐