返回顶部

Educational Codeforces Round 49 (Rated for Div. 2) D. Mouse Hunt (tarjan缩点)

  • 题意:有一只老鼠,有\(n\)个位置,刚开始老鼠可能出现在任意位置,然后每次跑去第\(a_i\)个位置,如果\(i=a_i\)那么它就会停下,你可以在第\(i\)个位置花费\(c_i\)放置老鼠夹,你想要话费最小的代价来保证能抓到老鼠,问最小代价是多少.

  • 题解:我们可以把数组\(a\)抽象成一张有向图,容易发现,对于一条链,我们只要在链末放一个夹子就够了,因为假如老鼠在链末,它哪儿都不能去,那么链末就一定要放一个夹子,而这条链上的所有点都会走到链末,那么只要链末有一个就够了.对于强连通分量,我们可以用tarjan缩点,同时维护强连通分量中的最小值,那么最后我们只要求一下所有出度为\(0\)的点的花费即可.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int n;
    int c[N];
    int dfn[N],low[N],timestamp;
    int stk[N],top;
    bool in_stk[N];
    int id[N],scc_cnt;
    vector<int> edge[N];
    int res[N];
    int out[N];
     
    void tarjan(int u){
    	dfn[u]=low[u]=++timestamp;
    	stk[++top]=u,in_stk[u]=true;
    	for(auto w:edge[u]){
    		if(!dfn[w]){
    			tarjan(w);
    			low[u]=min(low[u],low[w]);
    		}
    		else if(in_stk[w]) low[u]=min(low[u],dfn[w]);
    	}
     
    	if(dfn[u]==low[u]){
    		++scc_cnt;
    		int y;
    		do{
    			y=stk[top--];
    			in_stk[y]=false;
    			id[y]=scc_cnt;
    			res[scc_cnt]=min(res[scc_cnt],c[y]);
    		}while(u!=y);
    	}
    }
     
     
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	int n;
    	cin>>n;
    	me(res,INF,sizeof(res));
     
    	rep(i,1,n) cin>>c[i];
    	rep(i,1,n){
    		int v;
    		cin>>v;
    		edge[i].pb(v);
    	}
     
    	rep(i,1,n){
    		if(!dfn[i]) tarjan(i);
    	}
     
    	rep(i,1,n){
    		for(auto w:edge[i]){
    			int fu=id[i];
    			int fv=id[w];
    			if(fu==fv) continue;
    			out[fu]++;
    		}
    	}
     
    	int ans=0;
     
    	rep(i,1,scc_cnt){
    		if(out[i]) continue;
    		ans+=res[i];
    	}
    	
    	cout<<ans<<'\n';
    		
        return 0;
    }
    
    
posted @ 2021-04-29 16:59  _Kolibri  阅读(55)  评论(0)    收藏  举报