AcWing 第 92 场周赛 C题 4866. 最大数量 题解

原题链接

链表 + 并查集乱搞做法:

思路

首先可以发现,想要让度数尽量大,那我们应该构造成菊花图,即下图所示:

对于每个需求,我们可以知道,如果之前他们没有连在一起,那我们一定得把他们连在一起,该过程使用并查集维护。

如果他们已经连接了,实际上我们就多出来一条“自由边”。

对于自由边,如何进行利用呢,肯定是将包含点数最多的几个菊花团连在一起,重新组合形成一个大的菊花最好。

于是有了以下做法:

对于每个询问,如果两点之间不在同一菊花内,直接进行连接,同时把其中一点从链表中删去,这表示该点不为菊花的中心。

如果两点已经在同一菊花内了,将自由边数\(num\)加一,同时将链表内节点以儿子数进行排序,并将前\(num + 1\)个累加作为答案输出(加一是因为 num 是合并的次数,合并 num 次实际上应该有 num + 1团菊花)

代码

#include <bits/stdc++.h>
#define MAXn 1010
using namespace std;

int n, d;

int fa[MAXn], deep[MAXn], num;

int paixu[MAXn], cnt;//重排序数组

struct point
{
    int front, behind;
}p[MAXn];//链表节点


inline int getfa(int x)//并查集
{
    if(x == fa[x])
        return fa[x];
    return fa[x] = getfa(fa[x]);
}

bool com(int a, int b){ return a > b;}//从大到小排序

int main()
{
    cin >> n >> d;
    for(int i = 1; i <= n; i++)
    {
        p[i].front = i - 1;
        p[i].behind = i + 1;
        fa[i] = i;
        deep[i] = 1;
    }
    p[0].behind = 1;
    p[n + 1].front = n;//初始化
    
    while(d--)
    {
        int x, y;
        cin >> x >> y;
        int fa_x = getfa(x), fa_y = getfa(y);
        if(fa_x != fa_y)//不在联通块内
        {
            fa[fa_y] = fa_x;
            deep[fa_x] += deep[fa_y];//合并,注意看清不用上面并给x,下面加给y了
            p[p[fa_y].front].behind = p[fa_y].behind;
            p[p[fa_y].behind].front = p[fa_y].front;//从链表中删除
        }
        else num++;//在,自由边加1
        int i = p[0].behind;//开始遍历链表
        cnt = 0;
        while(i <= n)
        {
            paixu[++cnt] = deep[i];
            i = p[i].behind;
        }
        sort(paixu + 1, paixu + cnt + 1, com);//排序
        int ans = paixu[1];
        for(int i = 2; i <= num + 1; i++)
        {
            ans += paixu[i];
        }//利用自由边
        
        cout << ans - 1 << "\n";//减一是因为,我们统计时是用的连通块大小,但是题目问的是度的大小
    }
    
    return 0;
}
posted @ 2023-02-25 21:00  six_one  阅读(36)  评论(0编辑  收藏  举报