codeforce-884C

codeforce-884C

题 意:n个车站,每个车站都有一辆车从这里出发,到达的目的地为pi,每一个车站一定有某一俩车的目的地是这个车站。即一定存在i = pj。方便度即有序对(i,j)的个数,从i出发到达j。现在允许改变两个pj 但是也一定要符合要求。求最大的方便度。
输入已经符合要求。更改pj之后也要符合要求
输入范围:
1<=n<=1e5
1<=pi<=n
输入样例:

3
2 1 3

输出样例:

9

思 路:发现这其实是一个联通问题,如果把一个联通快中的一个pi改变为pj,那么就必须把原来指向pj的那个pm改成指向为pi。这样才符合题意,也就是说其实就是联通了连个联通快。那么怎么让方便度最大呢,当然是合并两个最大的联通快。这样方便度就等于每个联通快中站的数目的平方和。关键点是构造联通快,联通快的数目。

//
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+5;
typedef long long ll;
int pre[maxn];
int n;
int a[maxn];
int mp[maxn];
void init(){
    memset(mp,0,sizeof(mp));
    for(int i=1;i<=n;i++)pre[i] = i;
}
int find(int x){
    if(pre[x] == x){
        return x;
    }else return pre[x] = find(pre[x]);
}
void unit(int x,int y){
    int fx = find(x),fy = find(y);
    if(fx!=fy){
        pre[fx] = fy;
    }
}
bool cmp(int x,int y){
    return x>y;
}
int main(){
    scanf("%d",&n);
    init();
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        unit(i,a[i]);
    }
    for(int i=1;i<=n;i++){
        int temp = find(a[i]);
        mp[temp]++;
    }
    int number = 0;
    for(int i=1;i<=n;i++){
        if(mp[i] > 0) number++;
    }
    sort(mp+1,mp+n+1,cmp);
    ll sum = 0;
    for(int i=1;i<=2;i++){
        sum += mp[i];
    }
    sum = sum*sum;
    for(int i=3;i<=number;i++){
        sum += (ll)mp[i]*(ll)mp[i];
    }
    printf("%lld\n",sum);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37129433/article/details/81098356
今日推荐