现在的位置: 首页 > 综合 > 正文

ZOJ 3649 Social Net 最大生成树 + 并查集维护

2018年04月25日 ⁄ 综合 ⁄ 共 2785字 ⁄ 字号 评论关闭

题意:给定一个n(2<=n<=30000)个点m(n<=m<=50000)条边的无向图,选出权值和最大的生成树,给q(1<=q<=30000)个询问u->v路径上顺序

         得到的ci cj(i <= j)的cj - ci最大值是多少。

题解:kruskal搞掉最大生成树,并查集维护up[] dw[] ma[] mi[] 分别表示从当前点走到lca的最优值,从lca走到当前点的最优值,从当点走到lca的最大值,

         从lca走到当前点的最小值即可。 

         PS:比赛的时候把并查集搞错了唉,但是还是搞到了这个fb。


Sure原创,转载请注明出处。

#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#define MAX(a , b) ((a) > (b) ? (a) : (b))
#define MIN(a , b) ((a) < (b) ? (a) : (b))
using namespace std;
const int maxm = 50002;
const int maxn = 30002;
struct record
{
    int u,v,w;
    bool operator < (const record &other) const
    {
        return w > other.w;
    }
}EE[maxm];
struct node
{
    int v;
    int next;
}edge[maxn << 1];
struct QQ
{
    int u,v,id;
    int next;
}query[maxn << 1];
struct LL
{
    int have,next;
}lca[maxn];
int head[maxn],qhead[maxn],lcahead[maxn];
int angry[maxn],father[maxn],ans[maxn];
int ma[maxn],mi[maxn],up[maxn],dw[maxn];
bool vis[maxn];
int m,n,idx,tot,top,sum;

void swap(int &a,int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
    return;
}

void init()
{
    memset(head,-1,sizeof(head));
    memset(qhead,-1,sizeof(qhead));
    memset(lcahead,-1,sizeof(lcahead));
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        father[i] = i;
    }
    idx = tot = top = sum = 0;
    return;
}

int gg(int u)
{
    return (u == father[u]) ? father[u] : (father[u] = gg(father[u]));
}

void read()
{
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&angry[i]);
        ma[i] = mi[i] = angry[i];
        up[i] = dw[i] = 0;
    }
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d %d %d",&EE[i].u,&EE[i].v,&EE[i].w);
    }
    sort(EE , EE + m);
    return;
}

void addedge(int u,int v)
{
    edge[idx].v = v;
    edge[idx].next = head[u];
    head[u] = idx++;

    edge[idx].v = u;
    edge[idx].next = head[v];
    head[v] = idx++;
    return;
}

void addquery(int u,int v,int num)
{
    query[tot].u = u;
    query[tot].v = v;
    query[tot].id = num;
    query[tot].next = qhead[u];
    qhead[u] = tot++;

    query[tot].u = v;
    query[tot].v = u;
    query[tot].id = num;
    query[tot].next = qhead[v];
    qhead[v] = tot++;
    return;
}

void kruskal()
{
    for(int i=0;i<m;i++)
    {
        int x = gg(EE[i].u);
        int y = gg(EE[i].v);
        if(x != y)
        {
            sum += EE[i].w;
            father[y] = x;
            addedge(EE[i].u , EE[i].v);
        }
    }
    printf("%d\n",sum);
    return;
}

int find(int u)
{
    if(u == father[u]) return father[u];
    int tmp = father[u];
    father[u] = find(father[u]);
    up[u] = MAX(ma[tmp] - mi[u] , MAX(up[u] , up[tmp]));
    dw[u] = MAX(ma[u] - mi[tmp] , MAX(dw[u] , dw[tmp]));
    ma[u] = MAX(ma[u] , ma[tmp]);
    mi[u] = MIN(mi[u] , mi[tmp]);
    return father[u];
}

void dfs(int st)
{
    vis[st] = true;
    for(int i=qhead[st];i != -1;i=query[i].next)
    {
        if(vis[query[i].v])
        {
            int x = find(query[i].v);
            lca[top].have = i;
            lca[top].next = lcahead[x];
            lcahead[x] = top++;
        }
    }
    for(int i=head[st];i != -1;i=edge[i].next)
    {
        if(vis[edge[i].v] == false)
        {
            dfs(edge[i].v);
            father[edge[i].v] = st;
        }
    }
    for(int i=lcahead[st];i != -1;i=lca[i].next)
    {
        int id = lca[i].have;
        int u = query[id].u;
        int v = query[id].v;
        find(u);
        if(id & 1) swap(u , v);
        ans[query[id].id] = MAX(ma[v] - mi[u] , MAX(up[u] , dw[v]));
    }
    return;
}

void solve()
{
    scanf("%d",&m);
    int u,v;
    for(int i=0;i<m;i++)
    {
        scanf("%d %d",&u,&v);
        addquery(u,v,i);
    }
    for(int i=1;i<=n;i++)
    {
        father[i] = i;
    }
    dfs(1);
    for(int i=0;i<m;i++)
    {
        printf("%d\n",ans[i]);
    }
    return;
}

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        read();
        kruskal();
        solve();
    }
    return 0;
}

抱歉!评论已关闭.