UVA 11354 - Bond (最小生成树 + 树链剖分)

题目链接~~>

做题感悟:这题开始看到时感觉不是树不好处理,一想可以用 Kruskal 处理成树 ,然后就好解决了。

解题思路:

                先用 Kruskal 处理出最小生成树,然后用树链剖分 + 线段树处理就可以了。

代码:

#include<iostream>
#include<sstream>
#include<map>
#include<cmath>
#include<fstream>
#include<queue>
#include<vector>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<bitset>
#include<ctime>
#include<string>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std  ;
#define INT long long int
#define L(x)  (x * 2)
#define R(x)  (x * 2 + 1)
const int INF = 0x3f3f3f3f ;
const double esp = 0.0000000001 ;
const double PI = acos(-1.0) ;
const int mod = 1000000007 ;
const int MY = (1<<5) + 5 ;
const int MX = 100000 + 5 ;
int n ,m ,nx ,idx ,num ;
int head[MX] ,ti[MX] ,siz[MX] ,son[MX] ,father[MX] ,top[MX] ,dep[MX] ;
struct NODE
{
    int u ,v ,w ;
}e[MX] ;
struct MNODE
{
    int u ,v ,w ;
}t[MX] ;
struct Edge
{
    int u ,v ,w ,next ;
}E[MX*2] ;
void addedge(int u ,int v ,int w)
{
    E[num].v = v ; E[num].w = w ; E[num].next = head[u] ; head[u] = num++ ;
    E[num].v = u ; E[num].w = w ; E[num].next = head[v] ; head[v] = num++ ;
}
bool cmp(NODE a ,NODE b)
{
    return a.w < b.w ;
}
int find(int u)
{
    if(father[u] != u)
       return find(father[u]) ;
    else   return u ;
}
void Kruskal()
{
    nx = 1 ;
    int u ,v ,fa ,fb ;
    sort(e ,e+m ,cmp) ;
    for(int i = 0 ;i <= n ; ++i)
        father[i] = i ;
    for(int i = 0 ;i < m ; ++i)
    {
        u = e[i].u ; v = e[i].v ;
        fa = find(u) ;
        fb = find(v) ;
        if(fa != fb)
        {
            father[fa] = fb ;
            addedge(u ,v ,e[i].w) ;
            t[nx].u = u ; t[nx].v = v ; t[nx++].w = e[i].w ;
        }
    }
}
void dfs_find(int u ,int fa)
{
    dep[u] = dep[fa] + 1 ;
    father[u] = fa ;
    siz[u] = 1 ;
    son[u] = 0 ;
    for(int i = head[u] ;i != -1 ;i = E[i].next)
    {
        int v = E[i].v ;
        if(v == fa)  continue ;
        dfs_find(v ,u) ;
        siz[u] += siz[v] ;
        if(siz[son[u]] < siz[v])  son[u] = v ;
    }
}
void dfs_time(int u ,int fa)
{
    top[u] = fa ;
    ti[u] = idx++ ;
    if(son[u])   dfs_time(son[u] ,top[u]) ;
    for(int i = head[u] ;i != -1 ;i = E[i].next)
    {
        int v = E[i].v ;
        if(v == father[u] || v == son[u])  continue ;
        dfs_time(v ,v) ;
    }
}
struct node
{
    int le ,rt ,c ;
}T[MX*4] ;
void build(int i ,int le ,int rt)
{
    T[i].le = le ; T[i].rt = rt ;
    T[i].c = 0 ;
    if(le == rt)  return ;
    int Mid = (le + rt)>>1 ;
    build(L(i) ,le ,Mid) ;
    build(R(i) ,Mid+1 ,rt) ;
}
void update(int i ,int pos ,int w)
{
    if(T[i].le == T[i].rt)
    {
        T[i].c = w ;
        return ;
    }
    int Mid = (T[i].le + T[i].rt)>>1 ;
    if(pos <= Mid)   update(L(i) ,pos ,w) ;
    else     update(R(i) ,pos ,w) ;
    T[i].c = max(T[L(i)].c ,T[R(i)].c) ;
}
int section(int i ,int le ,int rt)
{
    if(T[i].le == le && T[i].rt == rt)
        return T[i].c ;
    int Mid = (T[i].le + T[i].rt)>>1 ;
    if(le > Mid)   return section(R(i) ,le ,rt) ;
    else if(rt <= Mid)  return section(L(i) ,le ,rt) ;
    else
          return max(section(L(i) ,le ,Mid) ,section(R(i) ,Mid+1 ,rt)) ;
}
int LCA(int u ,int v)
{
    int ans = 0 ;
    while(top[u] != top[v])
    {
        if(dep[top[u]] < dep[top[v]])
             swap(u ,v) ;
        ans = max(ans ,section(1 ,ti[top[u]] ,ti[u])) ;
        u = father[top[u]] ;
    }
    if(dep[u] > dep[v])  swap(u ,v) ;
    if(u != v)
        ans = max(ans ,section(1 ,ti[u]+1 ,ti[v])) ;
    return ans ;
}
int main()
{
    int u ,v ,Q ;
    bool first = false ;
    while(~scanf("%d%d" ,&n ,&m))
    {
        if(first) puts("") ;
        first = true ;
        num = 0 ;
        memset(head ,-1 ,sizeof(head)) ;
        for(int i = 0 ;i < m ; ++i)
           scanf("%d%d%d" ,&e[i].u ,&e[i].v ,&e[i].w) ;
        Kruskal() ;
        dep[1] = siz[0] = 0 ;
        dfs_find(1 ,1) ;
        idx = 1 ;
        dfs_time(1 ,1) ;
        build(1 ,1 ,n) ;
        for(int i = 1 ;i < nx ; ++i)
        {
            if(dep[t[i].u] < dep[t[i].v])
                swap(t[i].u ,t[i].v) ;
            update(1 ,ti[t[i].u] ,t[i].w) ;
        }
        scanf("%d" ,&Q) ;
        for(int i = 0 ;i < Q ; ++i)
        {
            scanf("%d%d" ,&u ,&v) ;
            printf("%d\n" ,LCA(u ,v)) ;
        }
    }
    return 0 ;
}

倍增法 (类似RMQ)

代码:

#include<iostream>
#include<sstream>
#include<map>
#include<cmath>
#include<fstream>
#include<queue>
#include<vector>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<bitset>
#include<ctime>
#include<string>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std  ;
#define INT long long int
#define L(x)  (x * 2)
#define R(x)  (x * 2 + 1)
const int INF = 0x3f3f3f3f ;
const double esp = 0.0000000001 ;
const double PI = acos(-1.0) ;
const int mod = 1000000007 ;
const int MY = (1<<5) + 5 ;
const int MX = 100000 + 5 ;
const int S = 20 ;
int n ,m ,idx ,num ,nx ;
int value[MX][25] ,p[MX][25] ,ti[MX] ,father[MX] ,dep[MX] ,head[MX] ;
struct TEMP
{
    int u ,v ,w ;
}A[MX] ;
struct Edge
{
    int v ,w ,next ;
}E[MX*2] ;
bool cmp(TEMP a ,TEMP b)
{
    return a.w < b.w ;
}
int find(int u)
{
    if(father[u] != u)
       return  find(father[u]) ;
    return u ;
}
void addedge(int u ,int v ,int w)
{
    E[num].v = v ; E[num].w = w ; E[num].next = head[u] ; head[u] = num++ ;
    E[num].v = u ; E[num].w = w ; E[num].next = head[v] ; head[v] = num++ ;
}
void Kruskal()
{
    nx = 1 ;
    int fa ,fb ;
    sort(A ,A+m ,cmp) ;
    for(int i = 0 ;i <= n ; ++i)
        father[i] = i ;
    for(int i = 0 ;i < m ; ++i)
    {
        fa = find(A[i].u) ;
        fb = find(A[i].v) ;
        if(fa != fb)
        {
            father[fa] = fb ;
            addedge(A[i].u ,A[i].v ,A[i].w) ;
        }
    }
}
void dfs_find(int u ,int fa ,int w)
{
    dep[u] = dep[fa] + 1 ;
    p[u][0] = fa ;
    value[u][0] = w ;
    for(int i = 1 ;i <= S ; ++i)
    {
        p[u][i] = p[p[u][i-1]][i-1] ;
        value[u][i] = max(value[u][i-1] ,value[p[u][i-1]][i-1]) ;
    }
    for(int i = head[u] ;i != -1 ;i = E[i].next)
    {
        int v = E[i].v ;
        if(v == fa)    continue ;
        dfs_find(v ,u ,E[i].w) ;
    }
}
int LCA(int u ,int v)
{
    int ans = 0 ;
    if(dep[u] > dep[v])  swap(u ,v) ;
    if(dep[u] < dep[v])
    {
        int d = dep[v] - dep[u] ;
        for(int i = 0 ;i <= S ; ++i)
          if(d&(1<<i))
          {
              ans = max(ans ,value[v][i]) ;
              v = p[v][i] ;
          }
    }
    if(u != v)
    {
        for(int i = S ;i >= 0 ; --i)
          if(p[u][i] != p[v][i])
          {
              ans = max(ans ,value[u][i]) ;
              ans = max(ans ,value[v][i]) ;
              u = p[u][i] ;
              v = p[v][i] ;
          }
        ans = max(ans ,value[u][0]) ;
        ans = max(ans ,value[v][0]) ;
    }
    return ans ;
}
void init()
{
    num = 0 ;
    memset(head ,-1 ,sizeof(head)) ;
    memset(ti ,0 ,sizeof(ti)) ;
    memset(value ,0 ,sizeof(value)) ;
    memset(p ,0 ,sizeof(p)) ;
    memset(dep ,0 ,sizeof(dep)) ;
}
int main()
{
    //freopen("input.txt" ,"r" ,stdin) ;
    int u ,v ,Q ;
    bool first = false ;
    while(~scanf("%d%d" ,&n ,&m))
    {
        if(first)  puts("") ;
        first = true ;
        init() ;
        for(int i = 0 ;i < m ; ++i)
           scanf("%d%d%d" ,&A[i].u ,&A[i].v ,&A[i].w) ;
        Kruskal() ;
        dep[1] = 0 ;
        dfs_find(1 ,1 ,0) ;
        scanf("%d" ,&Q) ;
        while(Q--)
        {
            scanf("%d%d" ,&u ,&v) ;
            printf("%d\n" ,LCA(u ,v)) ;
        }
    }
    return 0 ;
}

















 

你可能感兴趣的:(UVA 11354 - Bond (最小生成树 + 树链剖分))