管理者(最小生成树+rmq)
题目大意:
G同学是H市的管理者。H市有n个街区,m条双向道路,每条道路连接两个不同的街区,且没有两条道路连接两个一模一样的街区。保证任意两个街区能相互到达。
由于H市交通拥堵问题日益严重,G同学必须选择其中若干条道路升级为高速公路。升级后必须保证如果只走高速公路,任意两个街区都能相互到达。当然,每条道路升级为高速公路有不同的费用。同时由于未来的城市发展需要,可能要求某一条道路必须升级。问假如第i条道路一定要升级(1≤i≤m),最小花费是多少。1≤n≤2*10^5,n-1≤m≤2*10^5,每一条边费用<=10^9。
输入样例:
5 7
1 2 3
1 3 1
1 4 5
2 3 2
2 5 3
3 4 2
4 5 4
输出样例:
9
8
11
8
8
8
9
题解:
看到这道题,第一想法就是假如不强制某一条边一定要修建,那么就是一个简单的最小生成树问题。所以我们先建立一棵最小生成树,显然,假如一条边在这个最小生成树上,那么一定要修这条边的最小花费就是最小生成树的边权和。
那么问题来了,如果一条边不在这个最小生成树上呢?因为一定要加这一条边,所以我们就把这条边加进去,于是会形成一个环,我们的任务就是把环上最长的边删掉。对于这样一个环,它有一个性质:假如我们新加入的边连接u和v,那么环的范围就是u-Lca(u,v)-v,所以我们就可以用rmq来解决求最大值这个问题。
#include<iostream> #include<fstream> #include<algorithm> #include<cmath> #include<cstdio> #include<cstdlib> using namespace std; const int maxl = 20; int n,m,cur,head[800050],fa[800050][21],dep[800050],maxf[800050][21],vis[800020]; long long ans1,ans[800050]; struct tedge { int nex,to,val,num,fro; }e[805000]; struct data { int u,v,c,num; }p[800050]; void Add(int u,int v,int c,int num) { cur++; e[cur].to = v; e[cur].nex = head[u]; e[cur].val = c; e[cur].num = num; e[cur].fro = u; head[u] = cur; } bool cmp(data a,data b) { return (a.c<b.c||(a.c==b.c&&a.u<b.u)); } int Find(int x) { if (x==fa[x][0]) return x; fa[x][0] = Find(fa[x][0]); return fa[x][0]; } void Make_fa() { for (int i=1; i<=maxl; i++) for (int j=1; j<=n; j++) fa[j][i] = fa[fa[j][i-1]][i-1]; for (int i=1; i<=maxl; i++) for (int j=1; j<=n; j++) maxf[j][i] = max(maxf[j][i-1],maxf[fa[j][i-1]][i-1]); } void dfs(int root,int f) { dep[root] = dep[f]+1; for (int i=head[root]; i!=-1; i=e[i].nex) { int v = e[i].to; if (v==f) continue; if (vis[e[i].num]!=1) continue; fa[v][0] = root; maxf[v][0] = e[i].val; dfs(v,root); } } int Lca(int a,int b) { int u=a,v=b,cnt=0; if (dep[u]<dep[v]) swap(u,v); for (int i=maxl; i>=0; i--) if (dep[fa[u][i]]>dep[v]) { cnt = max(cnt,maxf[u][i]); u = fa[u][i]; } if (dep[u]>dep[v]) { cnt = max(cnt,maxf[u][0]); u = fa[u][0]; } if (u==v) return cnt; for (int i=maxl; i>=0; i--) if (fa[u][i]!=fa[v][i]) { cnt = max(cnt,maxf[u][i]); cnt = max(cnt,maxf[v][i]); u = fa[u][i]; v = fa[v][i]; } cnt = max(cnt,maxf[u][0]); cnt = max(cnt,maxf[v][0]); return cnt; } int main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout); scanf("%d%d",&n,&m); for (int i=0; i<=n; i++) head[i] = -1; for (int i=1; i<=m; i++) { int u,v,c; scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].c); p[i].num = i; } sort(p+1,p+1+m,cmp); for (int i=1; i<=m; i++) { Add(p[i].u,p[i].v,p[i].c,p[i].num); Add(p[i].v,p[i].u,p[i].c,p[i].num); } for (int i=1; i<=n; i++) fa[i][0] = i; for (int i=1; i<=cur; i++) { int u = Find(e[i].fro), v = Find(e[i].to); if (u==v) continue; ans1+=(long long)e[i].val; vis[e[i].num] = 1; fa[v][0] = u; fa[e[i].to][0] = u; } for (int i=1; i<=cur; i++) if (vis[e[i].num]==1) ans[e[i].num] = (long long)ans1; fa[1][0] = 0; maxf[1][0] = 0; dfs(1,0); Make_fa(); for (int i=1; i<=cur; i++) if (vis[e[i].num]!=1) { int maxe = 0; maxe = Lca(e[i].fro,e[i].to); ans[e[i].num] = (long long)ans1-maxe+e[i].val; i++; } for (int i=1; i<=m; i++) printf("%I64d\n",ans[i]); return 0; }