看似在搬luogu文章实则是在分享涩图吗?!

题解:P6486 [COCI 2010/2011 #4] DUGOVI

  • 本题解与其它大部分题解解法相同,此题解给出算法时间复杂度的证明。

    思路

  • 钱,则从 连一条有向边。统计每一点的入度
  • 若节点 的入度为 ,则 必须得到市长的帮助,答案直接加上 的出边。
  • 拿到钱的 会将钱分给他欠钱的人,于是我们暴力将钱沿着路线往下分。
  • 剩下的没环完的人一定在环上。
  • 遍历环,考虑给环上的一个人 补钱。设他现在有的钱为 ,他欠的钱为 ,欠他的钱为 。则
  • 补的钱为:
  • 给其它点补的钱为:
  • 总共补的钱为:

时间复杂度证明

  • 总时间复杂度:
  • 操作 :若节点 的入度为 ,则得到市长的帮助并暴力将钱沿着路线往下分。
  • 由于每人要么被市长给钱,要么被给钱,最多跑 次,所以操作 的复杂度为
  • 操作 :遍历环,考虑给环上的一个人 补钱。
  • 环最大长度为 ,而我们以 的时间计算贡献。因此时间复杂度为
  • 综上,时间复杂度为

代码

码风粗鄙。可参考其它题解的代码。

#include<bits/stdc++.h>
using namespace std;
int n;
int g[200005],c[200005];
int rd[200005];
int now[200005];
signed main(){
    cin>>n;
    int v;
    for(int i=1;i<=n;i++){
        cin>>g[i]>>c[i];
        rd[g[i]]++;
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        if(rd[i]==0){
            for(int u=i;rd[u]==0;u=g[u]){
                ans+=max(c[u]-now[u],0);
                rd[g[u]]--;
                now[g[u]]+=c[u];
                rd[u]=-1;
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(rd[i]>0){
            int maxn=2e9+10;
            int fa=i; 
            for(int u=g[i];rd[u];u=g[u]){
                ans+=max(c[u]-c[fa]-now[u],0);
                int z=max(c[u]-now[u],0)-max(c[u]-c[fa]-now[u],0);
                maxn=min(maxn,z);
                rd[u]--;
                fa=u;
            }
            ans+=maxn;
        }
    }
    cout<<ans;
    return 0;
}

photo_27616@07-07-2026_12-12-16_thumb.jpg
photo_27616@07-07-2026_12-12-16_thumb.jpg

添加新评论

文章目录