Tour【單調佇列】
阿新 • • 發佈:2022-05-18
題意
1號點為首都,其餘共n-1個點,每個點有一個上游城市\(f_i\),存在一條單向道路\(f_i \ -> \ i\)
現在可以從任何一個點出發開始沿著道路遊歷,且可以在任意城市終止
你擁有使用特權的機會,使用一次特權即可以從跳到另一個點開始繼續遊歷
問 使用0,1,2,。。。,n-1次遊歷機會分別最多能訪問多少個城市?
題解
首先,出於貪心的思想,先訪問城市最長的鏈,因為這樣增加一次遊歷機會可以訪問的城市是最多的。
我們可以首先用dfs求出從每個點開始往下訪問 能到達的最多城市數,將它們儲存進優先佇列(按照從該城市出發能訪問城市多的城市優先順序高的順序)。
訪問了佇列頭的元素後,標記所有的它這一條往下訪問的路上的點,表示這些點已經被訪問過,以後不需要再次訪問
code
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 200005,mod = 10007; int n,m,t,x; vector<int>e[N]; int f[N]; //從i出發最長的路徑 int son[N]; //i最長路徑下的兒子 bool vis[N]; int ans[N]; struct node{ int id; int dis; bool operator < (const node a) const{ return dis<a.dis; } }; void dfs(int now){ int mx=0; for(int i=0;i<e[now].size();i++){ int x=e[now][i]; dfs(x); if(f[x]>mx){ mx=f[x]; son[now]=x; } } f[now]=mx+1; } int main(){ scanf("%d",&n); for(int i=2,x;i<=n;i++){ scanf("%d",&x); e[x].push_back(i); } dfs(1); priority_queue<node,vector<node>,less<node> >q; for(int i=1;i<=n;i++) q.push({i,f[i]}); int cnt=0; while(!q.empty()){ int now=q.top().id; q.pop(); if(vis[now]){ continue; } vis[now]=1; if(!cnt) ans[cnt]=f[now]; else ans[cnt]=ans[cnt-1]+f[now]; cnt++; while(son[now]){ vis[son[now]]=1; now=son[now]; } } for(int i=0;i<n;i++){ if(i&&ans[i-1]==n) ans[i]=n; printf("%d\n",ans[i]); } return 0; }