NOIP2013D1T3货车运输(最大生成树+倍增lca)

传送门

这道题,先用kruskal求一遍图中的最大生成树。

然后,倍增求lca,求lca的同时求出边权的最小值。

#include <cstring>
#include <cstdio>
#include <algorithm>

int n, m, cnt, q, t, k;
int f[10001], head[100001], p[10001][21], minn[10001][21], deep[10001];
bool vis[10001];
struct node
{
    int x, y, z;
}tree[100001];
struct Node
{
    int next, to, val;
}edge[100001];

inline void add(int a, int b, int c)
{
    edge[cnt].val = c;
    edge[cnt].to = b;
    edge[cnt].next = head[a];
    head[a] = cnt++;
}

inline int father(int a)
{
    return a == f[a] ? a : f[a] = father(f[a]);
}

inline bool cmp(node a, node b)
{
    return a.z > b.z;
}

void kruskal()
{
    int i;
    for(i = 1; i <= m; i++)    scanf("%d %d %d", &tree[i].x, &tree[i].y, &tree[i].z);
    for(i = 1; i <= n; i++) f[i] = i;
    std::sort(tree + 1, tree + m + 1, cmp);
    for(i = 1; i <= m; i++)
    {
        int fa = father(tree[i].x), fb = father(tree[i].y);
        if(fa != fb)
        {
            f[fa] = fb;
            add(tree[i].x, tree[i].y, tree[i].z);
            add(tree[i].y, tree[i].x, tree[i].z);
        }
        if(k == n - 1) break;
    }
}

void dfs(int i)
{
    int j;
    vis[i] = 1;
    for(j = head[i]; j != -1; j = edge[j].next)
     if(!vis[edge[j].to])
     {
         deep[edge[j].to] = deep[i] + 1;
         p[edge[j].to][0] = i;
         minn[edge[j].to][0] = edge[j].val;
         dfs(edge[j].to);
     }
}

void init()
{
    int i, j;
    for(j = 1; (1 << j) <= n; j++)
     for(i = 1; i <= n; i++)
     {
         p[i][j] = p[p[i][j - 1]][j - 1];
         minn[i][j] = std::min(minn[i][j - 1], minn[p[i][j - 1]][j - 1]);
     }
}

int lca(int a, int b)
{
    int i, j, ret = 707406378;
    if(deep[a] < deep[b]) std::swap(a, b);
    for(i = 0; (1 << i) <= deep[a]; i++);
    i--;
    for(j = i; j >= 0; j--)
     if(deep[a] - (1 << j) >= deep[b])
     {
         ret = std::min(ret, minn[a][j]);
         a = p[a][j];
     }
    if(a == b) return ret;
    for(j = i; j >= 0; j--)
     if(p[a][j] != p[b][j])
     {
         ret = std::min(ret, std::min(minn[a][j], minn[b][j]));
         a = p[a][j];
         b = p[b][j];
     }
    ret = std::min(ret, std::min(minn[a][0], minn[b][0]));
    return ret;
}

int main()
{
    int i, j, x1, y1;
    scanf("%d %d", &n, &m);
    memset(head, -1, sizeof(head));
    //memset(minn, 127 / 3, sizeof(minn));
    kruskal();
    for(i = 1; i <= n; i++)
     if(!vis[i])
     {
         deep[i] = 1;
         dfs(i);
     }
    init();
    scanf("%d", &q);
    for(i = 1; i <= q; i++)
    {
        scanf("%d %d", &x1, &y1);
        if(father(x1) != father(y1)) printf("-1
");
        else printf("%d
", lca(x1, y1));
     }
    return 0;

}
View Code

换了写法

惨啊,

i >= 0 我居然nc的用 i 代替

应该是 i >= 1 用 i 代替

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 
  5 const int MAXN = 10001, MAXM = 50001, INF = 707406378;
  6 int n, m, q, cnt, tot;
  7 int head[MAXM], to[MAXM << 1], next[MAXM << 1], val[MAXM << 1];
  8 int f1[MAXN], f[MAXN][21], min[MAXN][21], deep[MAXN];
  9 
 10 struct node
 11 {
 12     int x, y, z;
 13 }p[MAXM];
 14 
 15 inline bool cmp(node a, node b)
 16 {
 17     return a.z > b.z;
 18 }
 19 
 20 inline void add(int x, int y, int z)
 21 {
 22     to[cnt] = y;
 23     val[cnt] = z;
 24     next[cnt] = head[x];
 25     head[x] = cnt++;
 26 }
 27 
 28 inline int find(int x)
 29 {
 30     return x == f1[x] ? x : f1[x] = find(f1[x]);
 31 }
 32 
 33 inline int Min(int x, int y)
 34 {
 35     return x < y ? x : y;
 36 }
 37 
 38 inline void swap(int &x, int &y)
 39 {
 40     x ^= y ^= x ^= y;
 41 }
 42 
 43 inline void dfs(int u)
 44 {
 45     int i, v;
 46     deep[u] = deep[f[u][0]] + 1;
 47     for(i = 0; f[u][i]; i++)
 48         f[u][i + 1] = f[f[u][i]][i],
 49         min[u][i + 1] = Min(min[u][i], min[f[u][i]][i]);
 50     for(i = head[u]; i ^ -1; i = next[i])
 51     {
 52         v = to[i];
 53         if(!deep[v])
 54         {
 55             f[v][0] = u;
 56             min[v][0] = val[i];
 57             dfs(v);
 58         }
 59     }
 60 }
 61 
 62 inline int lca(int x, int y)
 63 {
 64     int i, ans = INF;
 65     if(deep[x] < deep[y]) swap(x, y);
 66     for(i = 20; i >= 0; i--)
 67         if(deep[f[x][i]] >= deep[y])
 68             ans = Min(ans, min[x][i]), x = f[x][i];
 69     if(x == y) return ans == INF ? -1 : ans;
 70     for(i = 20; i >= 0; i--)
 71         if(f[x][i] ^ f[y][i])
 72             ans = Min(ans, min[x][i]),
 73             ans = Min(ans, min[y][i]),
 74             x = f[x][i], y = f[y][i];
 75     ans = Min(ans, min[x][0]);
 76     ans = Min(ans, min[y][0]);
 77     return ans == INF ? -1 : ans;
 78 }
 79 
 80 int main()
 81 {
 82     //freopen("truck.in", "r", stdin);
 83     //freopen("truck.out", "w", stdout);
 84     int i, x, y, fx, fy;
 85     scanf("%d %d", &n, &m);
 86     memset(head, -1, sizeof(head));
 87     memset(min, 127 / 3, sizeof(min));
 88     for(i = 1; i <= m; i++) scanf("%d %d %d", &p[i].x, &p[i].y, &p[i].z);
 89     std::sort(p + 1, p + m + 1, cmp);
 90     for(i = 1; i <= n; i++) f1[i] = i;
 91     for(i = 1; i <= m; i++)
 92     {
 93         fx = find(p[i].x);
 94         fy = find(p[i].y);
 95         if(fx ^ fy)
 96         {
 97             f1[fx] = fy;
 98             tot++;
 99             add(p[i].x, p[i].y, p[i].z);
100             add(p[i].y, p[i].x, p[i].z);
101         }
102         if(tot == n - 1) break; 
103     }
104     for(i = 1; i <= n; i++)
105         if(!deep[i])
106             dfs(i);
107     scanf("%d", &q);
108     for(i = 1; i <= q; i++)
109     {
110         scanf("%d %d", &x, &y);
111         if(find(x) ^ find(y)) puts("-1");
112         else printf("%d
", lca(x, y));
113     }
114     return 0;
115 }
View Code
原文地址:https://www.cnblogs.com/zhenghaotian/p/6667614.html