您的位置:首页 > 其它

CodeForces 609E Minimum spanning tree for each edge (lca+最小生成树+倍增)

2016-04-26 12:41 429 查看
题意:给出一个n个点m条边的无向图,问每条边所在的最小生成树的权值和是多少。

思路:首先求出整个图的最小生成树,然后对于任意一条边替换这条边两点到lca的最大边,这个值就是这条边所在的最小生成树的权值和,可以用倍增记录一下每个点的祖先和到这个祖先的最大边,然后处理出lca,对于每条边求出答案。

<pre class="cpp" name="code">#include <bits/stdc++.h>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#define pb push_back
#define mp make_pair
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 200100;
int n, m;
struct Edge {
int to, next;
int w;
} edge[MAXN*2];
int head[MAXN], tot;
void addedge(int u,int v,int w) {
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
struct Query
{
int q,next;
int index;//查询编号
} query[MAXN*2];
int h[MAXN];
int tt;
void add_query(int u,int v,int index)
{
query[tt].q = v;
query[tt].next = h[u];
query[tt].index = index;
h[u] = tt++;
query[tt].q = u;
query[tt].next = h[v];
query[tt].index = index;
h[v] = tt++;
}

void init()
{
tot = 0;
memset(head,-1,sizeof(head));
tt = 0;
memset(h,-1,sizeof(h));
}
//倍增
int fa[MAXN][20], max_edge[MAXN][20], dep[MAXN];
void init_fa(int u, int p, int c) {
dep[u] = dep[p] + 1;
fa[u][0] = p;
max_edge[u][0] = c;
for (int i = 1; fa[u][i-1]; i++) {
fa[u][i] = fa[ fa[u][i-1] ][i-1];
max_edge[u][i] = max(max_edge[u][i-1], max_edge[ fa[u][i-1] ][i-1]);
}
}

int cal(int u, int lca) {
int d = dep[u] - dep[lca];
int ans = 0;
for(int i = 18; i >= 0; i--) {
if ((1<<i) <= d) {
d -= (1<<i);
ans = max(ans, max_edge[u][i]);
u = fa[u][i];
}
}
return ans;
}

//lca
int pnt[MAXN], ans[MAXN];
bool vis[MAXN];
int find(int x) {
if(x == pnt[x]) return x;
return pnt[x] = find(pnt[x]);
}
void dfs(int u) {
vis[u] = 1;
pnt[u] = u;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(vis[v]) continue;
init_fa(v, u, edge[i].w);
dfs(v);
pnt[v] = u;
}
for(int i = h[u]; i != -1; i = query[i].next) {
int v = query[i].q;
if(vis[v]) ans[query[i].index] = find(v);
}
}

//最小生成树
int u[MAXN], v[MAXN], w[MAXN], p[MAXN], r[MAXN];
int find_p(int x) {
return x == p[x] ? x : p[x]=find_p(p[x]);
}
bool cmp(const int x, const int y) {
return w[x] < w[y];
}
LL kruscal() {
LL ans = 0;
for (int i = 1; i <= n; i++) p[i] = i;
for (int i = 1; i <= m; i++) r[i] = i;
sort(r+1, r+m+1, cmp);
for (int i = 1; i <= m; i++) {
int e = r[i];
int x = find_p(u[e]), y = find_p(v[e]);
if (x != y) {
p[x] = y;
ans += w[e];
addedge(u[e], v[e], w[e]);
addedge(v[e], u[e], w[e]);
}
}
return ans;
}
int main()
{
freopen("input.txt", "r", stdin);
scanf("%d%d", &n, &m);
init();
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u[i], &v[i], &w[i]);
add_query(u[i], v[i], i);
}
LL tmp = kruscal();
dfs(1);
for (int i = 1; i <= m; i++)
printf("%I64d\n", tmp+w[i]-max(cal(u[i], ans[i]), cal(v[i], ans[i])));
return 0;
}





                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息