zoukankan      html  css  js  c++  java
  • [2017浙工大之江学院决赛 H] qwb与学姐(并查集,按秩合并,最小生成树,LCA)

    题目链接:http://115.231.222.240:8081/JudgeOnline/problem.php?cid=1005&pid=7

    题意:中文题面。

    手动画一下会发现所求边必然存在于最大生成树上,那么就可以首先构造一棵最大生成树。

    问题转化成一棵树上求两个点之间的链上的最短边,用倍增lca就可以做了,但是我不会。

    于是可以考虑建树时的操作,在求最大生成树的时候按秩合并,即集合大的根要做集合小的根的父亲,这样连一条有向边。因为最大声成树是从大到小遍历的,所以能保证点与点相连的链上的最短的那条边一直被更新着,并且能够维持整棵树高不会超过log(n)。

    然后dfs预处理一下,查询的时候求lca,每次维护最短的边即可。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 typedef long long LL;
      5 typedef struct Edge {
      6     int u, v, w, next;
      7 }Edge;
      8 const int maxn = 50500;
      9 const int maxm = 200200;
     10 int h1[maxn], h2[maxn], pre[maxn], rk[maxn];
     11 int n, m, q, ecnt1, ecnt2;
     12 int depth[maxn], dis[maxn];
     13 Edge e[maxm<<1], ee[maxn<<1];
     14 
     15 void init() {
     16     for(int i = 1; i <= n; i++) pre[i] = i;
     17     memset(h1, -1, sizeof(h1));
     18     memset(h2, -1, sizeof(h2));
     19     memset(rk, 0, sizeof(rk));
     20     memset(depth, 0, sizeof(depth));
     21     memset(dis, 0, sizeof(dis));
     22     ecnt1 = ecnt2 = 0;
     23 }
     24 
     25 void a1(int u, int v, int w) {
     26     e[ecnt1].u = u, e[ecnt1].v = v, e[ecnt1].w = w;
     27     e[ecnt1].next = h1[u], h1[u] = ecnt1++;
     28 }
     29 
     30 void a2(int u, int v, int w) {
     31     ee[ecnt2].u = u, ee[ecnt2].v = v, ee[ecnt2].w = w;
     32     ee[ecnt2].next = h2[u], h2[u] = ecnt2++;
     33 }
     34 
     35 bool cmp(Edge a, Edge b) { return a.w > b.w; }
     36 int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); }
     37 
     38 int unite(int x, int y, int w) {
     39     x = find(x); y = find(y);
     40     if(x != y) {
     41         if(rk[x] >= rk[y]) {
     42             if(rk[x] == rk[y]) rk[x]++;
     43             pre[y] = x, a2(x, y, w);
     44         }
     45         else pre[x] = y, a2(y, x, w);
     46         return 1;
     47     }
     48     return 0;
     49 }
     50 
     51 void dfs(int u, int p) {
     52     for(int i = h2[u]; ~i; i=ee[i].next) {
     53         int v = ee[i].v, w = ee[i].w;
     54         if(p == v) continue;
     55         depth[v] = depth[u] + 1;
     56         dis[v] = w; pre[v] = u;
     57         dfs(v, u);
     58     }
     59 }
     60 
     61 int query(int u, int v) {
     62     int ret = 0x7f7f7f7f;
     63     if(depth[u] < depth[v]) swap(u, v);
     64     while(depth[u] > depth[v]) {
     65         ret = min(ret, dis[u]);
     66         u = pre[u];
     67     }
     68     while(u != v) {
     69         ret = min(ret, min(dis[u], dis[v]));
     70         u = pre[u]; v = pre[v];
     71     }
     72     return ret;
     73 }
     74 
     75 int main() {
     76     // freopen("in", "r", stdin);
     77     int u, v, w;
     78     while(~scanf("%d%d%d",&n,&m,&q)) {
     79         init();
     80         for(int i = 0; i < m; i++) {
     81             scanf("%d%d%d",&u,&v,&w);
     82             a1(u, v, w); a1(v, u, w);
     83         }
     84         sort(e, e+ecnt1, cmp);
     85         int mst = 0;
     86         for(int i = 0; i < ecnt1; i++) {
     87             u = e[i].u; v = e[i].v; w = e[i].w;
     88             if(unite(u, v, w)) mst += w;
     89         }
     90         int rt = find(1);
     91         memset(pre, -1, sizeof(pre));
     92         depth[rt] = 1;
     93         dfs(rt, 0);
     94         while(q--) {
     95             scanf("%d%d",&u,&v);
     96             printf("%d
    ", query(u, v));
     97         }
     98     }
     99     return 0;
    100 }
  • 相关阅读:
    大一训练赛20181105-二分三分分治部分
    该说命运弄人,毫不留情。
    矩阵快速幂模板
    Final Destination II -- 矩阵快速幂模板题
    UVA -580 组合数学
    NYOJ-16-矩形嵌套 记忆化搜索
    封装标签省,市,县。三级联动
    java压缩图片设置宽高
    sql分页
    常用的正则表达式@java后台
  • 原文地址:https://www.cnblogs.com/kirai/p/6935315.html
Copyright © 2011-2022 走看看