ICPC Latin American Regional 2017-Imperial roads(LCA)

简介: 题目大意:给出n个点,m条边的一个图,q个询问,每次询问给出两个点u,v,问包含u-v这条边的最小生成树是多少这道题比较板首先求一下这个图的最小生成树对于这n个点,最小生成树一定是n-1条边,如果说再加上一条边,一定会构成一个环。我们把生成的这个最小生成树看作是一个以1为根节点的最小生成树。所以说在下面的q个询问中,如果说这条边用到了最小生成树中(这条边是最小生成树上的边),那么直接输出当前最小生成树的代价就好;如果说当前这条边没有出现在最小生成树当中,那么最小生成树的权值val加上这条边之后就构成了一个环,求出这两个点所在的环内的最大边权,并将这个边权减去,就是最终结果

Description


The roads of Cubiconia are in a dire state, after years of neglect and lack of maintenance. Each road

connects two different cities A and B and can be traveled in both ways (from A to B or from B to A). There is at most one road between each pair of cities, and using the existing roads it is possible to travel between any pair of cities. The new emperor of Cubiconia has just raised the taxes (again!), but promised to repair at least some of the roads, guaranteeing that Cubiconians will be able to travel between any pair of cities using only restored roads. The Department of Public Works have calculated the cost of repairing each individual road. Now they want to calculate the minimum cost for repairing a set of roads so that the emperor’s promise is made true. This is not easy because the emperor wants the set of repaired roads to include one particular road, but he has not yet decided which particular road to include: could be the one that connects the city where his castle is to the city where his daughter’s royal residence is, or the road that connects the city where his summer palace is to the only city by the seaside, or. . . Fearing the emperor will take too long to decide, the engineers want your help. Given the description of the roads in Cubiconia, with their respective repairing costs, you must write a program to answer a set of queries. For each query you will be given one specific road that should be repaired, and must determine the minimum cost for repairing a set of roads (including the given specific road) so that Cubiconians will be able to travel between any pair of cities using only restored roads.


Input


The first line contains two integers N (2 ≤ N ≤ 105) and R (N − 1 ≤ R ≤ 2 × 105), representing respectively the number of cities and the number of roads in Cubiconia. Cities are identified by distinct integers from 1 to N. Each of the next R lines describes a road with three integers A, B (1 ≤ A < B ≤ N) and C (1 ≤ C ≤ 104 ), indicating that there is a road between cities A and B and the cost of repairing it is C. There is at most one road between each pair of cities, and using the existing roads it is


possible to travel between any pair of cities. The next line contains an integer Q (1 ≤ Q ≤ 105) representing the number of queries. Each of the next Q lines describes a query with two integers U and V (1 ≤ U < V ≤ N), indicating the specific road that should be repaired. There are no repeated queries.


Output


Output Q lines, each line with an integer indicating the answer to the corresponding query of the input, that is, the minimum cost for repairing a set of roads (including the specific road in the query) so that Cubiconians will be able to travel between any pair of cities using only restored roads.


样例输入


样例输入1:

3 3
1 2 10
2 3 5
1 3 7
3
2 3
1 2
1 3


样例输出1:

12
15
12


样例输入2:

4 4
1 2 1
2 4 1
2 3 100
1 4 50
1
1 4


样例输出2:

151


样例输入3:

5 7
1 2 8
1 3 10
2 4 5
2 3 12
4 5 4
3 5 14
1 5 20
3
2 3
1 5
3 5


样例输出3:

29
39
31


题目大意:


给出n个点,m条边的一个图,q个询问,

每次询问给出两个点u,v,问包含u-v这条边的最小生成树是多少


这道题比较板


首先求一下这个图的最小生成树对于这n个点,最小生成树一定是n-1条边,如果说再加上一条边,一定会构成一个环。


我们把生成的这个最小生成树看作是一个以1为根节点的最小生成树。

所以说在下面的q个询问中,如果说这条边用到了最小生成树中(这条边是最小生成树上的边),那么直接输出当前最小生成树的代价就好;如果说当前这条边没有出现在最小生成树当中,那么最小生成树的权值val加上这条边之后就构成了一个环,求出这两个点所在的环内的最大边权,并将这个边权减去,就是最终结果


那么如何求这两个点之间的最大边权呢?

看下面这张图;

20210516182721275.png

假如这就是我们求得的最小生成树(默认根为1),然后我们要求出包含10号节点到11号节点这条边的最小生成树:

先把10-11这条边加进去,很显然构成了4-5-7-8-10-11-6-4这样的一个环,为了要求得最小生成树,那么我们就要将这个环里面的最大边权得边给去掉,重点是我们如何找到这个边。

显然dfs一定会T飞,我们将这个环去掉10-11之后的状态看作是一个以4为根节点的树4更好就是这两个点的LCA,再求lca的过程中,我们就可以记录下最大值。用上倍增之后,复杂度是说的过去的。找到这个最大边权之后再减去就是最终答案。


Code:


int head[maxn],cnt;
struct node {
  int u,v,nex;
  ll w;
  friend bool operator <(node a,node b) {
    return a.w < b.w;
  }
} a[maxn],e[maxn];
void add(int u,int v,ll w){
  e[cnt].u = u;
  e[cnt].v = v;
  e[cnt].w = w;
  e[cnt].nex = head[u];
  head[u] = cnt ++;
}
int n,m,q;
int fa[maxn];
int maxi[maxn][30];
int beiz[maxn][30];
int depth[maxn];
void dfs(int u,int fa) {
  //beiz[u][0] = fa;
  for(int i=head[u]; ~i; i=e[i].nex) {
    int to = e[i].v;
    if(to == fa) continue;
    depth[to] = depth[u] + 1;
    beiz[to][0] = u;
    maxi[to][0] = e[i].w;
    for(int d=1; d<=19; d++) {
      beiz[to][d] = beiz[beiz[to][d-1]][d-1];
      maxi[to][d] = max(maxi[to][d-1],maxi[beiz[to][d-1]][d-1]);
    }
    dfs(to,u);
  }
}
int lca(int x,int y) {
  int ret = 0;
  if(depth[x] < depth[y]) swap(x,y);
  for(int i=19; i>=0; i--) {
    if(depth[beiz[x][i]] >= depth[y]) {
      ret = max(ret,maxi[x][i]);
      x = beiz[x][i];
    }
  }
  if(x == y) return ret;
  for(int i=19; i>=0; i--) {
    if(beiz[x][i] != beiz[y][i]) {
      int mx = max(maxi[x][i],maxi[y][i]);
      ret = max(ret,mx);
      x = beiz[x][i];
      y = beiz[y][i];
    }
  }
  return ret= max(ret,max(maxi[x][0],maxi[y][0]));
  ///return ret = Max(ret,maxi[x][0],maxi[y][0]);
}
int findFa(int x){
  if(x == fa[x]) return x;
  else return fa[x] = findFa(fa[x]);
}
typedef pair<int,int> PII;
map<PII,bool> kru;
map<PII,ll>wight;
int main() {
  cin >> n >> m;
  for(int i=1; i<=m; i++) {
    a[i].u=read,a[i].v=read,a[i].w=read;
    wight[{a[i].u,a[i].v}] = a[i].w;
    wight[{a[i].v,a[i].u}] = a[i].w;
  }
  memset(head,-1,sizeof head);
  sort(a+1,a+1+m);
  ll val = 0LL;
  for(int i=0;i<maxn;i++) fa[i] = i; 
  for(int i=1;i<=m;i++){
    int u = a[i].u;
    int v = a[i].v;
    int fau = findFa(u);
    int fav = findFa(v);
    if(fau == fav) continue;
    fa[fau] = fav;
    val += a[i].w;
    kru[{u,v}] = 1,kru[{v,u}] = 1;
    add(u,v,a[i].w),add(v,u,a[i].w);
  }
  depth[1] = 0;
  dfs(1,0); // 0 is the father of 1
  cin >> q;
  while(q --){
    int u=read,v=read;
    if(kru[{u,v}]) cout << val <<endl;
    else{
      int t = lca(u,v);
      // cout << t <<endl;
      cout << val + wight[{u,v}] - t<<endl;
    }
  }
  return 0;
}
/*
*/


目录
打赏
0
0
0
0
5
分享
相关文章
The Preliminary Contest for ICPC China Nanchang National Invitational J题 Distance on the tree
The Preliminary Contest for ICPC China Nanchang National Invitational J题 Distance on the tree
110 0
Constructing Roads(kruskal)
Constructing Roads(kruskal)
101 0
2020-2021 ACM-ICPC, Asia Seoul Regional Contest L. Two Buildings (决策单调性 分治)
2020-2021 ACM-ICPC, Asia Seoul Regional Contest L. Two Buildings (决策单调性 分治)
156 0
2020-2021 ACM-ICPC, Asia Seoul Regional Contest L. Two Buildings (决策单调性 分治)
ICPC North Central NA Contest 2018 G . Tima goes to Xentopia(最短路 空间优化 剪枝)
ICPC North Central NA Contest 2018 G . Tima goes to Xentopia(最短路 空间优化 剪枝)
89 0
POJ-2488,A Knight's Journey(DFS)
POJ-2488,A Knight's Journey(DFS)
Google Earth Engine ——MYD09GA.006 Aqua 地表反射率 Daily Global 1km and 500m在没有大气散射或吸收的情况下在地
Google Earth Engine ——MYD09GA.006 Aqua 地表反射率 Daily Global 1km and 500m在没有大气散射或吸收的情况下在地
251 0
Google Earth Engine ——MYD09GA.006 Aqua 地表反射率 Daily Global 1km and 500m在没有大气散射或吸收的情况下在地
[ICPC 46th Shanghai] Life is a Game 克鲁斯卡尔重构树
题目大意: 给定n个点,m条边,有q个询问 每个点有一个(能量值)点权,每条边有一个边权 m条边描述为u v w表示有一条u与v相连的边权为w的通路 在每一次询问中,给定一个点x和现有的能量值k,每次只能是在当前能量值大于边权的时候到达另一个点,并获取这个点的能量值(路可以重复走),问最终能够获得多大的能量值
151 0