Educational Codeforces Round 51 (Rated for Div. 2)E题

也许是一道码题

核心思路

直接floyd是肯定过不了的,注意到mn20m-n\leq20,那么这个图可以看做为一棵树和至多20条非树边构成的。那么在树上求距离就很简单了,对于剩下的20条非树边直接暴力从两个端点开始求一遍最短路,在所有经过至少一条非树边与树上距离中找到最小值即为答案。

uvu\to v至少经过一条(u0,v0)(u_0,v_0)的边的最小值为min{distid(u0)u+distid(v0)v}\min \{\mathrm{dist}_{id(u_0)}u+\mathrm{dist}_{id(v_0)}v\}

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define int ll

#define REP(i,e,s) for(register int i=e; i<=s; i++)
#define DREP(i,e,s) for(register int i=e; i>=s; i--)
#define ll long long
#define DE(...) fprintf(stderr,__VA_ARGS__)
#define DEBUG(a) DE("DEBUG: %d\n",a)
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
int read() {
int x=0,f=1,ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

const int MAXN=200000+10,INF=0x3f3f3f3f3f3f3f;

struct edge {
int u,v,w;
} a[MAXN];

int f[MAXN];

int find(int x) {
if(f[x]==x) return x;
return f[x]=find(f[x]);
}

int link(int x,int y) {
f[find(x)]=find(y);
}

int head[MAXN],_next[MAXN<<1],to[MAXN<<1],weigh[MAXN<<1],cnt;

void addedge(int u,int v,int w) {
cnt++;
_next[cnt]=head[u];
head[u]=cnt;
to[cnt]=v;
weigh[cnt]=w;
}

queue<int> q1;

int n,m,dept[MAXN],dis[MAXN],fa[MAXN][25];

void bfs(int s) {
q1.push(s);
while(!q1.empty()) {
int u=q1.front();q1.pop();
for(int i=head[u]; i; i=_next[i]) {
int v=to[i];
if(fa[u][0]==v) continue;
fa[v][0]=u;
dept[v]=dept[u]+1;
dis[v]=dis[u]+weigh[i];
q1.push(v);
}
}
}

priority_queue<pair<int,int> > q;

int book[MAXN],dist[44][MAXN];

void dij(int op,int s) {
q.push(make_pair(0,s));
REP(i,1,n) book[i]=0;
REP(i,1,n) dist[op][i]=INF;
dist[op][s]=0;
while(!q.empty()) {
int u=q.top().second;q.pop();
if(book[u]) continue;
book[u]=1;
for(int i=head[u]; i; i=_next[i]) {
int v=to[i];
if(dist[op][v]>dist[op][u]+weigh[i]) {
dist[op][v]=dist[op][u]+weigh[i];
q.push(make_pair(-dist[op][v],v));
}
}
}
return ;
}

int used[MAXN];

int lca(int u,int v) {
if(dept[u]>dept[v]) swap(u,v);
int len=dept[v]-dept[u];
DREP(i,19,0) if((1<<i)&len) v=fa[v][i];
if(u==v) return u;
DREP(i,19,0) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
return fa[u][0];
}

signed main() {
n=read(),m=read();
REP(i,1,m)
a[i].u=read(),a[i].v=read(),a[i].w=read();

REP(i,1,n) f[i]=i;

int num=0;

REP(i,1,m) {
if(find(a[i].u)==find(a[i].v)) continue;
link(a[i].u,a[i].v);
addedge(a[i].u,a[i].v,a[i].w);
addedge(a[i].v,a[i].u,a[i].w);
used[i]=1;
num++;
if(num==n-1) break;
}
bfs(1);
REP(j,1,19) REP(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1];


REP(i,1,m)
if(!used[i])
addedge(a[i].u,a[i].v,a[i].w),addedge(a[i].v,a[i].u,a[i].w);
int op=0;
REP(i,1,m) {
if(!used[i]) {
dij(++op,a[i].u);
dij(++op,a[i].v);
}
}
int q=read();
REP(i,1,q) {
int u=read(),v=read();
int ans=dis[u]+dis[v]-2*dis[lca(u,v)];
REP(j,1,op) ans=min(ans,dist[j][u]+dist[j][v]);
printf("%lld\n",ans);
}

return 0;
}

评论