日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

魔方俱乐部

發布時間:2023/12/3 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 魔方俱乐部 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

爆肝感動三更

  • 題目
  • 思路
  • 90分代碼(MLE)
  • 題解
  • 代碼實現

題目

fateice 來到了魔方俱樂部旅行。
魔方俱樂部有N個分部,每個分部均有且僅有一個蟲洞,但是這蟲洞只能通往一個分部。

每個分部有一個 orzFang 價值,第i個分部的 orzFang 價值為A[i]。

現在他想知道,從第i個分部出發,并只通過蟲洞前往下一個分部,orzFang 價值之和最多是多少(到達一個分部多次只計算1次 orzFang 價值)。

輸入格式
第一行為一個正整數N 。
第二行有N個非負整數A[i] ,表示了每個分部的 orzFang 價值。
第三行有N個正整數F[i] ,表示通過第i個分部的蟲洞所到達的分部為F[i] ,可能出現F[i]=i的情況。
輸出格式
包括N行,第i行包含一個非負整數,表示從第i個分部出發,orzFang 價值之和的最大值為多少。

樣例
樣例輸入
8
5 4 3 2 1 1 1 1
2 3 1 1 2 7 6 8
樣例輸出
12
12
12
14
13
2
2
1
數據范圍與提示
對于20%的數據,N≤10。
對于40%的數據,N≤1000。
對于100%的數據,1≤N≤2e5,1≤Ai≤104

思路

首先看到這種帶環的,而且i只會有一個F[i],
蒟蒻就自然而然的想到了tarjan,對于這種環也就是強連通分量,
于是就往下寫了縮點,最后用記憶化搜索去得到每一個i的ans

可就是莫名其妙就MLE,

90分代碼(MLE)

如果有大佬知道蒟蒻MLE于何處,必當萬分感謝!!!

#include <stack> #include <cstdio> using namespace std; #define MAXN 200001 stack < int > q; int n, cnt; int orz[MAXN], f[MAXN]; int scc[MAXN], ans[MAXN]; bool in_queue[MAXN];void tarjan ( int u ) {if ( scc[u] )return;if ( in_queue[u] ) {cnt ++;int head;while ( ! q.empty() && q.top() != u ) {head = q.top();scc[head] = cnt;ans[cnt] += orz[head];q.pop();}head = q.top();scc[head] = cnt;ans[cnt] += orz[head];q.pop();while ( ! q.empty() )q.pop();return;}in_queue[u] = 1;q.push ( u );tarjan ( f[u] );in_queue[u] = 0; }int dfs ( int u ) {if ( ans[scc[u]] )return ans[scc[u]];return ans[scc[u]] = dfs ( f[u] ) + orz[u]; }int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &orz[i] );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &f[i] );for ( int i = 1;i <= n;i ++ ) {if ( ! scc[i] ) tarjan ( i );if ( ! scc[i] )scc[i] = ++ cnt;}for ( int i = 1;i <= n;i ++ )if ( f[i] == i )printf ( "%d\n", orz[i] );elseprintf ( "%d\n", dfs ( i ) );return 0; }

題解

AC思路就是,通過題意,很容易發現數據長得是格外好看

描述一下就是多個環,然后環上套了幾條鏈
極端數據F[i]=i,就有可能是一條單鏈加一個自環,也不影響

對于這種一條條的單鏈,我們可以思考拓撲排序,甩到棧里面去
為什么是棧呢?
因為棧是先進后出,后進先出,我們正好要得到后進的F[i]答案再去更新i的答案

然后,就只剩下一個又一個互不打擾的環了,
因為是環,所以從環上任意一個點都可以開始搜索更新答案
我們可以用隊列來模擬,把這個環上的節點在dfs更新ans的時候
順便記錄一下經過哪些節點,最后把隊列清空的時候就順便更新一下ans[i]

環處理好了的話就回到了之前棧的處理上,從后往前掃棧,直接更新ans[i]就可以了
可以保證i能走到的蟲洞都已經有了答案

代碼實現

#include <cstdio> #include <queue> #include <stack> using namespace std; #define MAXN 200005 queue < int > q; stack < int > sta; int n; int d[MAXN], f[MAXN], orz[MAXN], ans[MAXN]; bool vis[MAXN];void Top_sort () {for ( int i = 1;i <= n;i ++ )if ( ! d[i] )q.push ( i );while ( ! q.empty() ) {int t = q.front();q.pop();sta.push( t );d[f[t]] --;if ( ! d[f[t]] )q.push( f[t] );} } void dfs ( int u, int root ) {if ( vis[u] )return;vis[u] = 1;ans[root] += orz[u];q.push( u );dfs ( f[u], root ); } void circle () {for ( int i = 1;i <= n;i ++ )if ( d[i] && ! vis[i] ) {dfs ( i, i );while ( ! q.empty() ) {int t = q.front();q.pop();ans[t] = ans[i];}} }int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &orz[i] );for ( int i = 1;i <= n;i ++ ) {scanf ( "%d", &f[i] );d[f[i]] ++;}Top_sort ();circle ();while ( ! sta.empty() ) {int t = sta.top();sta.pop();ans[t] = orz[t] + ans[f[t]];}for ( int i = 1;i <= n;i ++ )printf ( "%d\n", ans[i] );return 0; }

就這樣就能AC,所以為什么我的tarjan不可以,啊啊啊啊!!!

總結

以上是生活随笔為你收集整理的魔方俱乐部的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。