Tour【单调队列】
题意
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;
}

浙公网安备 33010602011771号