CCPC-Wannafly Winter Camp Day8 (Div2, onsite) A 题 Aqours (精巧的树形DP)
題目鏈接: https://www.cometoj.com/contest/29/problem/A?problem_id=414
Aqours
題目描述
Aqours 正在 LoveLive! 決賽中表演,舞臺可以看作是一棵 nn 個點(diǎn)的有根樹,其中根節(jié)點(diǎn)是 1 號點(diǎn),ii 號點(diǎn)的父親節(jié)點(diǎn)為 p_ip
i
?
,保證 1 \le p_i < i1≤p
i
?
<i,而且對于 2 \le i < j \le n2≤i<j≤n 有 p_i \le p_jp
i
?
≤p
j
?
。
其中的葉子節(jié)點(diǎn)(定義為沒有孩子節(jié)點(diǎn)的點(diǎn))是與粉絲進(jìn)行互動的節(jié)點(diǎn),Aqours 會在這些葉子節(jié)點(diǎn)之間走動來與更多的粉絲互動,但是她們又要唱歌又要跳舞,要盡快節(jié)省走動時間,然后也要做到雨露均沾,所以每次要往編號更小的葉子節(jié)點(diǎn)走。
所以 Aqours 想知道對于每一個葉子節(jié)點(diǎn) uu,離它最近的編號 < u<u 的葉子節(jié)點(diǎn)到它的距離是多少,若不存在則視距離為 -1。
輸入描述
第一行一個正整數(shù) n (1 \le n \le 3 \times 10^6)n(1≤n≤3×10
6
),表示樹的大小。
第二行 n-1n?1 個正整數(shù),其中第 ii 個數(shù)表示 p_{i+1}(1 \le p_{i+1} \le i)p
i+1
?
(1≤p
i+1
?
≤i)。
對于 2 \le i < j \le n2≤i<j≤n,保證 p_i \le p_jp
i
?
≤p
j
?
。
輸出描述
每個葉子對應(yīng)的答案輸出一行。每行第一個數(shù)是葉子節(jié)點(diǎn)的編號 uu,第二個數(shù)是離他最近的編號 < u<u 的葉子節(jié)點(diǎn)到它的距離,若不存在則輸出 -1。
要求按葉子節(jié)點(diǎn)編號從小到大輸出。
樣例輸入 1
10
1 1 1 1 2 4 5 6 7
樣例輸出 1
3 -1
8 3
9 4
10 4
思路:
對于題面的這句話,我們可以把給定的點(diǎn)序列看為數(shù)的BFS序。
我們維護(hù)一個信息 dp[i] 代表距離第i個節(jié)點(diǎn)最近的葉子節(jié)點(diǎn)的距離。
我們從1到n,掃每一個葉子節(jié)點(diǎn)Y,我們向上(它的父節(jié)點(diǎn))dfs,dfs過程中維護(hù)f的值,直到遇到一個已經(jīng)訪問(被其他節(jié)點(diǎn)dfs過得)的節(jié)點(diǎn) X 。那么當(dāng)前節(jié)點(diǎn)的答案就是 dp[X] +Y到X節(jié)點(diǎn)的步數(shù)。
同時還需要回溯更新dp[i] 的信息。
為什么正確?
1、我們是從1到n逐一掃描每一個葉子 節(jié)點(diǎn)Y,所以當(dāng)一個葉子節(jié)點(diǎn)向上dfs的過程中遇到了一個已經(jīng)放過的節(jié)點(diǎn)X時,X節(jié)點(diǎn)一定是被編號比Y小的節(jié)點(diǎn)更新的。所以保證了題目的要求。
2、我們在dfs過程中同時回溯維護(hù)dp[i] 的信息,就保證了dp[i] 即可以是其他節(jié)點(diǎn)通過先上后下到達(dá)的,也可以是下方的節(jié)點(diǎn)一直向上走到達(dá)的。
這樣保證了dp[i] 的正確性。
細(xì)節(jié)見代碼:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define rt return #define dll(x) scanf("%I64d",&x) #define xll(x) printf("%I64d\n",x) #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl using namespace std; typedef long long ll; 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;} ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;} inline void getInt(int* p); const int maxn = 3000010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ int du[maxn]; int far[maxn]; bool vis[maxn]; int n; int ans; int dp[maxn]; int dfs(int id,int step) {if(vis[id]){ans=dp[id]+step;return dp[id]+1;}else{int temp=inf;dp[id]=step;vis[id]=1;if(id!=1){temp=dfs(far[id],step+1);}if(temp<dp[id])dp[id]=temp;return dp[id]+1;} } int main() {//freopen("D:\\code\\text\\input.txt","r",stdin);//freopen("D:\\code\\text\\output.txt","w",stdout);gg(n);int x;repd(i,2,n){gg(x);du[x]++;far[i]=x;}repd(i,1,n){ans=-1;if(du[i]==0){dfs(i,0);printf("%d %d\n",i,ans);}}return 0; }inline void getInt(int* p) {char ch;do {ch = getchar();} while (ch == ' ' || ch == '\n');if (ch == '-') {*p = -(getchar() - '0');while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 - ch + '0';}}else {*p = ch - '0';while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 + ch - '0';}} }轉(zhuǎn)載于:https://www.cnblogs.com/qieqiemin/p/11251645.html
總結(jié)
以上是生活随笔為你收集整理的CCPC-Wannafly Winter Camp Day8 (Div2, onsite) A 题 Aqours (精巧的树形DP)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 走台阶 OR 台阶走——《狂人C》习题解
- 下一篇: 牛客假日团队赛5 LCatch That