【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 }

猜你喜欢

转载自www.cnblogs.com/xiefengze1/p/10793002.html