ACM-ICPC北京赛区2017网络同步赛I

http://hihocoder.com/contest/icpcbeijing2017/problem/9

求每种颜色平均出现的次数

首先模拟一轮1-n,x点最后的颜色记为fax 这样意味着下一次1-n,点x的颜色取决于当前fax的颜色

然后会发现这是一个环套树,我们首先获得一个联通块内环的大小,要知道只有环上的颜色有用,并且贡献都一样,因为只有环上的颜色会一直打转,其他地方的颜色会被覆盖,而且这个联通块的循环节是 n*环的大小,考虑某一个1-n的轮回,如果a点颜色是1,那么与a点距离是环的大小的整数倍的点,都是1,这样对联通块做了一个分割,当我们考虑循环节是n*环的大小时,颜色1会在每个联通块的点都出现一次,不重复不遗漏,这样我们把(n*环的大小)拍扁了成了n次操作,

考虑1-n轮时的一个点的一条边,如果u,v是同一个联通块的,那么其实对答案统计是没用影响的,假设u,v是同一联通块的颜色1,2,如果当前操作把颜色2染成1,那么总有一个时刻颜色1会在v上被染成同一联通块的颜色,总和其实没有变化,所以我们着眼与不同联通块之间的操作,当一个联通块因为当前操作少了一个点的时候,我们要处理出来这个联通块last与now时间内的正确之,就是 经过时间*每个时间的点树=这段时间的总点数,用last与nowsize维护一下总点数就行了

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
using namespace std;
typedef long  long int ll;
const int maxn = 1e5+9;
int fa[maxn],vis[maxn];
int color[maxn],ccnt;
int last[maxn],cnt[maxn];
int size[maxn];
ll cot[maxn];
int nowsize[maxn];
double ans[maxn];
stack<int> stak;
vector<int> vv[maxn];
void cal(int now,int color){
    cot[color]+=(ll)(now-last[color])*nowsize[color];
    last[color] = now;
}
int main(int argc, const char * argv[]) {
    int n,m;
    while (~scanf("%d%d",&n,&m)) {
        for(int i=1;i<=n;i++){
            vv[i].clear();
            fa[i] = i;
            vis[i] = 0;
            color[i] = 0;
            last[i] = 0;
            cnt[i] = 0;
            cot[i] = 0;
            nowsize[i] = 0;
        }
        ccnt = 0;
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            vv[u].push_back(v);
            vv[v].push_back(u);
        }
        for(int i=1;i<=n;i++){
            for(int v: vv[i]){
                fa[v] = fa[i];
            }
        }
        for(int i=1;i<=n;i++){
            if(vis[i]==0){
                int x = i;
                while (!stak.empty()) {
                    stak.pop();
                }
                while (vis[x]==0) {
                    stak.push(x);
                    vis[x] = 1;
                    if(vis[fa[x]]==0)
                    x = fa[x];
                }
                x = fa[x];
                if(color[x]!=0) {
                    while (!stak.empty()) {
                        int t = stak.top();
                        color[t] = color[x];
                        stak.pop();
                    }
                }else{
                    ccnt++;
                    size[ccnt] = 1;
                    while (stak.top()!=x) {
                        size[ccnt]++;
                        int t = stak.top();
                        color[t] = ccnt;
                        stak.pop();
                    }
                    while (!stak.empty()) {
                        int t = stak.top();
                        color[t] = ccnt;
                        stak.pop();
                    }
                }
            }
        }
        for(int i=1;i<=n;i++){
            nowsize[color[i]]++;
            
        }
        for(int i=1;i<=n;i++){
            for(int v: vv[i]){
                if(color[i]!=color[v]){
                    cal(i-1, color[i]);
                    cal(i-1, color[v]);
                    nowsize[color[i]]++;
                    nowsize[color[v]]--;
                    color[v] = color[i];
                }
            }
        }
        for(int i=1;i<=ccnt;i++){
            cal(n, i);
        }
        int pp = 0;
        for(int i=1;i<=ccnt;i++){
            for(int j=0;j<size[i];j++){
                ans[pp++] =cot[i] *1.0/n/size[i];
            }
        }
        sort(ans,ans+pp);
        for(int i=pp-1;i>=0;i--){
            printf("%.6f\n",ans[i]);
        }
    }
    return 0;
}

/*
 6 6
 1 3
 3 5
 5 2
 2 4
 4 6
 6 1
 
 */

  

 

猜你喜欢

转载自www.cnblogs.com/tjucxz/p/8903071.html