Tour【单调队列】
题意
1号点为首都,其余共n-1个点,每个点有一个上游城市\(f_i\),存在一条单向道路\(f_i \ -> \ i\)
现在可以从任何一个点出发开始沿着道路游历,且可以在任意城市终止
你拥有使用特权的机会,使用一次特权即可以从跳到另一个点开始继续游历
问 使用0,1,2,。。。,n-1次游历机会分别最多能访问多少个城市?
题解
首先,出于贪心的思想,先访问城市最长的链,因为这样增加一次游历机会可以访问的城市是最多的。
我们可以首先用dfs求出从每个点开始往下访问 能到达的最多城市数,将它们保存进优先队列(按照从该城市出发能访问城市多的城市优先级高的顺序)。
访问了队列头的元素后,标记所有的它这一条往下访问的路上的点,表示这些点已经被访问过,以后不需要再次访问
code
#include
#define ll long long
using namespace std;
const int N = 200005,mod = 10007;
int n,m,t,x;
vectore[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 dismx){
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,less >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