Description
llyllylly最近发明了一个叫瞬移方块的游戏,为啥llyllylly这么闲呢,这得从一只蝙蝠说起.....
llyllylly决定给大家也分享一下这个游戏,游戏规则是这样的,有一个长度为nnn的方块序列,每个方块有对应的能量值aia_iai,游戏就是获取最大的能量值,但是只能选择mmm个位置,如果方块就是这样静止不动的话,也太简单了,聪明的llyllylly显然不会玩这么弱智的游戏,这个游戏的方块能量是可以瞬移的!!(所以才叫瞬移方块嘛),对于当前位置的idiid_iidi你会知道他下一瞬间会瞬移到哪个位置(就是能量瞬移),我们能做的就是选好mmm个位置,无论瞬移否,这个位置任意时刻的能量值我们都可以获取,那么请大家开始愉快的玩耍吧。
Input
第一行包含两个整数n,(1≤n,m≤105)n,(1 \leq n,m \leq 10^5)n,(1≤n,m≤105)。
第二行有nnn个整数表示第iii个位置的方块能量值为ai,(1≤ai≤105)a_i,(1 \leq a_i \leq 10^5)ai,(1≤ai≤105)。
第三行有nnn个整数表示第iii个位置的方块下一瞬间会瞬移到的位置idi,(1≤idi≤n)id_i,(1 \leq id_i \leq n)idi,(1≤idi≤n)。
Output
输出包含一个整数即答案。
Hint
对于第一个样例:我们可以选择第222和第888方块的位置获取任意时刻的能量值,答案为1+2+3+4+5+6+7+8=36
对于第二个样例:我们可以选择第333和第888方块的位置获取任意时刻的能量值,答案为1+2+3+4+12=22
Source
nuoyanli
思路
-
题意:给我们一个 n 个数的序列代表n个位置,每个位置包含一定的能量,这些能量在每一瞬间会转移,怎么转移呢?之后又给了一个长为n的序列br【】,在这个序列中 br[ i ] = x 也就是 第i个位置的能量最终会转移到 x 位置,这样经过了无线多个瞬间之后,那么能量就可以认为是保持确定位置了
-
思路:这一题真是挺不错的,巧妙的把
并查集
的知识融入到题目中,如果我们用并查集的思想去理解这一题,那么问题就简单了,我们把 两个位置之间进行能量转化, 看作一对关系把它们放入同一个集合中去,当对n个位置都进行合并集合操作之后, 那么我们只需要讨论 每个集合中 能量的综合就行了(巨弱的我咋没想到,,不过还是要感谢lly学张的 精心出题)
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define ll long long
const int Len = 1e5 + 10;
ll ar[Len];
ll br[Len];
ll sum[Len];
ll find(ll x) { return x == br[x] ? x : br[x] = find(br[x]); }
void Union(int x, int y)
{
ll fx = find(x);
ll fy = find(y);
if(fx != fy)
br[fx] = fy;
}
void init()
{
for(int i = 0; i < Len; i ++)
br[i] = i;
}
int main()
{
/* freopen("A.txt","r",stdin); */
init(); //初始化并查集中的元素,不要忘了
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i ++)
scanf("%lld", &ar[i]);
int next;
for(int i = 1; i <= n; i ++)
{
scanf("%d", &next);
Union(i, next);
}
for(int i = 1; i <= n; i ++)
sum[find(br[i])] += ar[i]; //遍历每个节点,把属于同一个集合的点加入到相同的下标sum
sort(sum + 1, sum + 1 + n, greater<ll>());
ll ans = 0;
for(int i = 1; i <= m; i ++)
ans += sum[i];
printf("%lld\n", ans);
return 0;
}