我是靠谱客的博主 开放小伙,最近开发中收集的这篇文章主要介绍C. Bertown Subway(带权并查集),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题面如下

在这里插入图片描述

题意简说


给你 n n n 个位置
i i i 个位置有一个数 a i a_i ai
位置 i i i 可以到达位置 a i a_i ai
你可以最多改变两个位置的 a i a_i ai 的值
问:
最多存在多少对 ( x , y ) (x, y) (x,y) [ x x x y y y, x 与 y x与y xy可以相等]


题解or思路


我们可以发现路一定是成环的,可能存在多个环。

如果一个环有 n u m num num 个点
那么这个环的贡献就是 n u m ∗ n u m num * num numnum 个方案数
a n s = a n s + n u m ∗ n u m ans = ans + num * num ans=ans+numnum

如果环数 ≥ 2 ge 2 2
我们可以把最大的两个环拼接成一个大环(通过改变 a i a_i ai的值)
约定:两个最大的环的点数分别是 a   b a b a b
那么贡献应该是减去两环的贡献 + 新大环的贡献
a n s = a n s − a ∗ a + b ∗ b ans = ans - a*a + b*b ans=ansaa+bb
a n s = a n s + ( a + b ) ∗ ( a + b ) ans = ans + (a+b)*(a + b) ans=ans+(a+b)(a+b)


AC代码如下:

int n;
int f[N], num[N];
int find(int x)
{
   return f[x] == x ? x : f[x] = find(f[x]);
}
void solve()
{
   cin >> n;
   vector<int> v;
   for (int i = 1; i <= n; i++)
       f[i] = i, num[i] = 1;
   int ans = 0;
   for (int i = 1; i <= n; i++)
   {
       int tt;
       cin >> tt;
       int a = find(i), b = find(tt);
       if (a != b)
       {

           f[a] = b;
           num[b] += num[a];
       }
       else
       {
           ans += num[a] * num[a];
           v.push_back(num[a]);
       }
   }
   sort(v.begin(), v.end());
   if (v.size() >= 2)
   {
       int a = v.back();
       v.pop_back();
       int b = v.back();
       v.pop_back();

       ans -= (a * a + b * b);
       ans += (a + b) * (a + b);
   }

   cout << ans << 'n';
}

最后

以上就是开放小伙为你收集整理的C. Bertown Subway(带权并查集)的全部内容,希望文章能够帮你解决C. Bertown Subway(带权并查集)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部