首页 > 其他分享 >题解:AT_joisc2019_k 合併 (Mergers)

题解:AT_joisc2019_k 合併 (Mergers)

时间:2024-10-22 20:48:54浏览次数:8  
标签:int 题解 joisc2019 tot add dfn low bri Mergers

题目传送门

前言

联考题,被初一的我切了。看到题解区里没有 Tarjan 做法,于是来补一篇 Tarjan 题解。

分析

因为相同州的城市不会分裂,所以可以给相同州的成市连边(注意不是两两连边,连成一个环就行),发现把国家分成两个部分就相当于断掉一条道路。那么如果整个国家就是一个边双连通分量,就不可能分裂。

于是我们可以先给图边双连通分量缩点,可以发现缩点后两个点中城市所属的州一定不相同。合并两个州的操作相当于在缩点后给两个点连边。然后就可以用经典的答案统计法了:设缩点后度数为 \(1\) 的节点有 \(s\) 个,则需要连的边数为 \(\lceil \frac{s}{2} \rceil\) 个。

代码

#include <bits/stdc++.h>
using namespace std;
#define N 1000010
int n, K, a[N], hd[N], ikun[N], nxt[N * 7], to[N * 7], tot = 1, fa[N], dep[N], dfn[N], low[N], pre[N], idx, c[N], sum, mkp[N], ans;
bool bri[N * 7], vis[N];
inline void add(int u, int v)
{
    tot++;
    nxt[tot] = hd[u];
    to[tot] = v;
    hd[u] = tot;
}
inline void tarjan(int x, int frm) // 跑 Tarjan,找割边
{
    dfn[x] = ++idx;
    low[x] = idx;
    for (int i = hd[x]; i; i = nxt[i])
    {
        int y = to[i];
        if (i == frm || (i ^ 1) == frm) // 注意重边!
        {
            continue;
        }
        if (!dfn[y])
        {
            tarjan(y, i);
            low[x] = min(low[x], low[y]);
            if (low[y] > dfn[x])
            {
                bri[i] = 1;
                bri[i ^ 1] = 1;
            }
        }
        else
        {
            low[x] = min(low[x], dfn[y]);
        }
    }
}
inline void dfs(int x) // 找到割边后缩点
{
    c[x] = sum;
    for (int i = hd[x]; i; i = nxt[i])
    {
        if (bri[i] || bri[i ^ 1])
        {
            continue;
        }
        int y = to[i];
        if (!c[y])
        {
            dfs(y);
        }
    }
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> K;
    for (int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        add(u, v);
        add(v, u);
    }
    for (int i = 1; i <= n; i++) // 读入所属州并连边
    {
        cin >> a[i];
        ikun[a[i]] = i;
        if (pre[a[i]])
        {
            add(i, pre[a[i]]);
            add(pre[a[i]], i);
        }
        pre[a[i]] = i;
        fa[i] = i;
        dep[i] = 1;
    }
    for (int i = 1; i <= n; i++) // 要连成环
    {
        if (pre[i])
        {
            add(pre[i], ikun[i]);
            add(ikun[i], pre[i]);
        }
    }
    tarjan(1, 0);
    for (int i = 1; i <= n; i++)
    {
        if (!c[i])
        {
            sum++;
            dfs(i);
        }
    }
    if (sum == 1)
    {
        cout << 0;
        return 0;
    }
    ans = sum;
    for (int i = 1; i <= n; i++)
    {
        for (int j = hd[i]; j; j = nxt[j])
        {
            int k = to[j];
            if (c[i] != c[k])
            {
                if (mkp[c[i]] && (mkp[c[i]] != c[k])) // 判断点的度数是否为 1
                {
                    if (!vis[c[i]])
                    {
                        ans--;
                        vis[c[i]] = 1;
                    }
                }
                if (mkp[c[k]] && (mkp[c[k]] != c[i]))
                {
                    if (!vis[c[k]])
                    {
                        ans--;
                        vis[c[k]] = 1;
                    }
                }
                mkp[c[i]] = c[k];
                mkp[c[k]] = c[i];
            }
        }
    }
    cout << (ans + 1) / 2;
    return 0;
}

标签:int,题解,joisc2019,tot,add,dfn,low,bri,Mergers
From: https://www.cnblogs.com/awmmmmmm/p/18493710

相关文章

  • 题解:P11207 「Cfz Round 9」Rose
    可以考虑把字符串\(s\),\(t\)按\(s_1t_1s_2t_2\dotss_nt_n\)拼接,记为\(a\)。为了方便表述,这里分别把PVW表示为012。Subtask0我会暴力!可以直接在\(a\)上进行dfs,复杂度为\(O(3^{2n})\)。Subtask1我会找性质!注意到答案只有可能是\(0,1,2\),因为在最坏情况下,只......
  • 题解:P11204 「Cfz Round 9」Lone
    首先可以观察出把木棍平均分是最优的。然后平均分后最多只有两种长度的木棒,长度分别为\(\lfloor\frac{m}{n}\rfloor\)和\(\lfloor\frac{m}{n}\rfloor+1\)。最后check一下就行了。代码:#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#define......
  • P2934 [USACO09JAN] Safe Travel G 题解
    一个用平衡树,不用脑子的写法。(目前没有用平衡树的诶。)题意不经过最短路的最后一条边的最短路,保证最短路唯一。思路看到最短路唯一容易想到建出的最短路DAG其实是最短路树(以\(1\)为根)。那题意转化为求每个节点不经过与父亲的连边,所能到根节点的最短路。容易发现每个点的......
  • 【NOIP2021】方差 题解
    前言题目链接:洛谷;LOJ;UOJ。题意简述给你单调不降序列\(\{a_n\}\),你可以让\(a_i\getsa_{i-1}+a_{i+1}-a_i\),求操作后方差的最小值。\(n\leq10^4\),\(1\leqa_i\leq600\)。题目分析仔细观察操作,发现实际上是将\(a_i\)按照\(a_{i-1}\)和\(a_{i+1}\)的......
  • 题解:P10977 Cut the Sequence
    题目传送门分析看到这种题就可以想到动态规划,先设状态:$f_i$表示考虑前$i$个数,所需要的最小代价。发现$f_i$可以从所有$i$以前的状态加后一段区间转移过来,于是可以列出状态转移方程:$$f_i=\min_{j=i-1}^{s_i-s_j\leqm}(f_j+\max_{k=j+1}^i)$$其中$j$......
  • [题解]P2671 [NOIP2015 普及组] 求和
    P2671[NOIP2015普及组]求和可以发现我们对相同颜色且编号奇偶性相同的元素归为一组,组内的元素两两都满足题目条件,且这样可以不重不漏覆盖所有答案。设分完组之后,某一组内的元素编号分别是\(a_1,a_2,\dots,a_q\),数字分别是\(b_1,b_2,\dots,b_q\),则根据题意,该组的答案是:\[\lar......
  • 20241021 校测T1 致敬传奇捆绑测试题目(Perm) 题解
    题解:致敬传奇捆绑测试题目Perm来自不知道什么时候的回忆。给定正整数\(n\),一个\(1\simn\)的排列\(p\)是一个好排列,当且仅当使得对于任意\(1\lek<n\),都有\(\sum_{i=1}^kp_i>p_{k+1}\)。现在请你求出字典序第小的好排列\(p\)。\(1\len\le10^6\),\(1\lek\le......
  • [ARC133E] Cyclic Medians 题解
    一点不会套路。思路对于中位数相关,发现我们不好直接表示与中位数有关的内容。不妨枚举\(x\),把大于\(x\)的标为\(1\),小于等于\(x\)的标为\(0\),这样把所有最终为一的方案数加起来就是原来的答案。大概是这样一个东西:\[k=\sum_{i=0}^k[i<k]\]这个怎么求呢。发现若一组......
  • Public NOIP Round #7 T3 黑白棋子 题解
    Description有一棵\(n\)个点的树,顶点的编号为\(1\)到\(n\)。对于树中的每个顶点,可能存在一个白色的棋子、一个黑色的棋子,或者没有棋子。树上正好有\(w\)个白色棋子和\(b\)个黑色棋子。另外,对于每一对具有相同颜色棋子的顶点,存在一条路径,路径上的每个顶点都包含相同颜色......
  • AT_agc064_c [AGC064C] Erase and Divide Game 题解
    先考虑所有\(l_i=r_i\)时怎么做,可以建出反向Trie树,问题转化为从根开始每次向左子树或右子树走,第一个拿到空子树的人输,直接在Trie上dp即可。考虑从叶子层开始对每一层的点合并两个子树的dp值,发现每一层值相同的连续段是较少的。于是可以维护这些连续段,每次合并要将每个......