第一行包含两个正整数N和K。(1<=K<=N<=100000)。 接下来一行包含N个正数,每个数不超过1000000,表示每个城市的吸引力的值。 再接下来(N - 1)行,每行时两个不超过(N - 1)的非负整数,表示道路。
一行包含一个整数,表示满足要求的旅行计划中最多能选择的城市数量。
7 5 6 2 7 5 6 5 2 3 1 1 0 0 2 2 4 4 5 4 6
4
题解:将所有点按v从大到小排序,每次扩展价值相同的点,c1表示当前连通块的个数,只有当i==0||c1==1时(即上一步扩展的点全部连通时)才进行ans更新.
eg:样例 第一次扩展 2(7) 2(7) ans=1,c1=1;
第二次扩展 0(6) 4(6) 0(6)---------2(7)--------4(6) ans=3,c1=1;
第三次扩展 3(5) 5(5) 3(5) 0(6)---------2(7)--------4(6)----------5(5) ans=4,c1=2;
dfs()的返回值为连接所有大于vmin点的个数.
用到dfs()的情况:k=3;
1(5)-----2(4)-----3(5)----4(6) 第二次扩展后 1(5) 3(5)----4(6) ans=2<k;
| 第三次扩展后 1(5)-----2(4)-----3(5)----4(6) dfs()=4>k,所以ans不能更新.若k=4,则ans=k;
5(4) |
5(4)
#include<iostream>
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int n,kk,c1,c2,ans,Max,v[maxn],id[maxn],fa[maxn],sz[maxn];
bool vis[maxn],is[maxn];
vector<int> e[maxn];
bool cmp(int a,int b){
return v[a]>v[b];
}
int getfa(int x){
int c,a=x;
while(x!=fa[x]) x=fa[x];
while(x!=fa[a]) c=fa[a],fa[a]=x,a=c;
return x;
}
void mer(int a,int b,int x){
a=getfa(a),b=getfa(b);
if(v[a]>v[b]) swap(a,b);
fa[a]=b;
sz[b]+=sz[a];
if(v[a]==x) c2--;
else c1--;
}
int dfs(int u,int f){
int ret=1;
bool flag=v[u]>Max;
for(int i=0;i<e[u].size();i++){
int w=e[u][i];
if(w==f||!is[w]) continue;
int s=dfs(w,u);
if(s) ret+=s,flag=1;
}
return flag?ret:0;
}
int main(){
scanf("%d%d",&n,&kk);
for(int i=0;i<n;i++){
scanf("%d",&v[i]);
id[i]=fa[i]=i;
sz[i]=1;
}
sort(id,id+n,cmp);
for(int u,v,i=1;i<n;i++){
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=0,j=0;i<n;i=j){
while(j<n&&v[id[i]]==v[id[j]]) j++;
for(int k=i;k<j;k++){
int w=id[k];
vis[w]=1;
c2++;
for(int a=0;a<e[w].size();a++){
int u=e[w][a];
if(vis[u]) mer(w,u,v[w]);
}
}
if(!i) for(int k=0;k<j;k++) ans=max(ans,sz[getfa(id[k])]);
else if(c1==1){
int s=sz[getfa(id[0])];
if(s<=kk) ans=max(ans,s);
else{
for(int k=0;k<j;k++) is[k]=1;
Max=v[id[i]];
int z=dfs(id[0],-1);
if(z<=kk) ans=kk;
break;
}
}
c1+=c2;
c2=0;
}
printf("%d\n",ans);
}