【xsy1300】 原题的旅行 最短路+倍增
题目大意:有一个$n$个点,$m$条边的无向图,玩家走过第$i$条边,血槽中的血会下降$v_i$点,如果不足$v_i$点,这人会当场去世。
这$n$个点中,有若干个是关键点,在这些关键点可以将血槽补满。
现在有$q$组询问,每次问一个玩家的血槽至少需要多大,才能从$x$走到$y$。
保证$x$号点和$y$号点可以把你的血槽补满
数据范围:$n≤10^5$,$m≤2\times 10^5$,$V≤10^9$。
我们考虑如果每个点都能补满血槽的话,我们显然可以对原图求一遍最小生成树,每次我们在这颗树上倍增取最大值即可。
不过这一题非常烦人,只有一部分点是可以的。
我们考虑对每个点i处理出$dist[i]$和$from[i]$。
其中,$from[i]$表示距离$i$号点最近的可以补满$i$号点血槽的点的编号,$dist[i]$表示$i$号点距离$from[i]$的距离。
对于原图中任意一条边$(u,v,w)$,若满足$from[u]!=from[v]$,那么我们就在新图中加入$(from[u],from[v],dist[u]+dist[v]+w)$
然后,我们对新图求一个最小生成树,然后在这棵树上倍增即可。
时间复杂度显然是$O((m+n+q)\log\ n)$的。
1 #include<bits/stdc++.h> 2 #define L long long 3 #define M 200005 4 #define INF (1LL<<60) 5 using namespace std; 6 7 struct edge{L u,v,next;}e[M*4]={0}; L head[M]={0},use=0; 8 void add(L x,L y,L z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;} 9 L dist[M]={0},from[M]={0}; 10 L n,m; L ok[M]={0},vis[M]={0};char c[M]={0}; 11 12 struct node{ 13 L u,bel; L dis; 14 node(){u=bel=dis=0;} 15 node(L U,L Bel,L Dis){u=U; bel=Bel; dis=Dis;} 16 friend bool operator <(node a,node b){ 17 return a.dis>b.dis; 18 } 19 }; priority_queue<node> q; 20 21 void dij(){ 22 memset(dist,1,sizeof(dist)); 23 for(L i=1;i<=n;i++) if(ok[i]) q.push(node(i,i,0)); 24 while(!q.empty()){ 25 node U=q.top(); q.pop(); 26 L u=U.u; if(dist[u]!=dist[0]) continue; 27 dist[u]=U.dis; 28 from[u]=U.bel; 29 for(L i=head[u];i;i=e[i].next) 30 if(dist[u]+e[i].v<=dist[e[i].u]){ 31 q.push(node(e[i].u,U.bel,dist[u]+e[i].v)); 32 } 33 } 34 } 35 36 struct edge2{ 37 L u,v;L w; 38 edge2(){u=v=w=0;} 39 edge2(L U,L V,L W){u=U; v=V; w=W;} 40 friend bool operator <(edge2 a,edge2 b){return a.w<b.w;} 41 }p[M*2]; L N=0; 42 43 L fa[M]={0}; L get(L x){return x==fa[x]?x:fa[x]=get(fa[x]);} 44 45 L f[M][20]={0},dep[M]={0}; L mx[M][20]={0}; 46 void dfs(L x,L fa,L F){ 47 f[x][0]=fa; dep[x]=dep[fa]+1; mx[x][0]=F; 48 for(L i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1],mx[x][i]=max(mx[x][i-1],mx[f[x][i-1]][i-1]); 49 for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa) dfs(e[i].u,x,e[i].v); 50 } 51 L getlca(L x,L y){ 52 if(dep[x]<dep[y]) swap(x,y); L cha=dep[x]-dep[y]; 53 for(L i=19;~i;i--) if((1<<i)&cha) x=f[x][i]; 54 for(L i=19;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 55 if(x==y) return x; return f[x][0]; 56 } 57 L jump(L x,L k){ 58 L maxn=0; 59 for(L i=19;~i;i--) if((1<<i)&k){ 60 maxn=max(maxn,mx[x][i]); 61 x=f[x][i]; 62 } 63 return maxn; 64 } 65 66 main(){ 67 scanf("%lld%lld",&n,&m); 68 scanf("%s",c+1); for(L i=1;i<=n;i++) ok[i]=(c[i]=='1'); 69 for(L i=1,x,y,z;i<=m;i++) scanf("%lld%lld%lld",&x,&y,&z),add(x,y,z),add(y,x,z); 70 dij(); 71 for(L x=1;x<=n;x++) 72 for(L i=head[x];i;i=e[i].next) if(i&1){ 73 L X=x,Y=e[i].u; 74 if(from[X]!=from[Y]){ 75 p[++N]=edge2(from[X],from[Y],dist[X]+dist[Y]+e[i].v); 76 } 77 } 78 sort(p+1,p+N+1); 79 memset(head,0,sizeof(head)); use=0; memset(e,0,sizeof(e)); 80 for(L i=1;i<=n;i++) fa[i]=i; 81 82 for(L i=1;i<=N;i++){ 83 L u=get(p[i].u),v=get(p[i].v); 84 if(u==v) continue; fa[u]=v; 85 u=p[i].u; v=p[i].v; 86 add(u,v,p[i].w); add(v,u,p[i].w); 87 } 88 L sta=0; for(L i=1;i<=n;i++) if(ok[i]) {sta=i; break;} 89 90 dfs(sta,0,0); 91 92 L q; scanf("%lld",&q); 93 while(q--){ 94 L x,y; scanf("%lld%lld",&x,&y); 95 L lca=getlca(x,y); 96 printf("%lld\n",max(jump(x,dep[x]-dep[lca]),jump(y,dep[y]-dep[lca]))); 97 } 98 }