题意:给一个n,接着输入n个数,表示n个点的值,接着输入n-1条边形成一个生成树
问最大有多少个点的集合使得该集合内的所有点都满足如下:对于集合内点大小相邻的两个点,该两点之间经过的所有点的大小都小于该两点
eg 7
3 30 350 100 200 300 400
1 2 2 3 3 4 4 5 5 6 6 7
该无向图可表示为1——2——3——4——5——6——7
取点6对于集合(3-7)来说,正好比他大的点为点3,且他们之间的所有点的
大小都小于该两点,满足条件
同理取该集合内的其他点也满足条件
所有这个集合所有点满足条件,所以最大值为5(计算其他集合发现没有更大的集合满足上述条件)
分析:该题可以转换为,建有向图,对于一条边点值小的指向大的边,求由一
个点出发可以走过的最多的点数
如样例图为1->2->3<-4->5->6->7 当取点4时能经过5个点
注意:用深搜写要手动扩栈,并且要有C++交,不然会RE暴栈,用bfs写不会
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#pragma comment(linker,"/STACK:102400000,102400000") //手动扩栈
using namespace std;
const int maxn = 5e5+5;
int E = 0;
int w[maxn];
int num[maxn];
int pnt[maxn*2],nxt[maxn*2],head[maxn*2];
void add(int u,int v) //邻接表
{
nxt[E]=head[u];
pnt[E]=v;
head[u]=E++;
}
void dfs(int u){ //深搜
num[u]++;
for(int i=head[u];i!=-1;i=nxt[i]){
int v=pnt[i];
if(!num[v]) dfs(v);
num[u]+=num[v]; //加上邻接点走过的个数
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
E=0;
memset(head,-1,sizeof(head));
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
if(w[u]<w[v]) add(u,v);
else add(v,u);
}
int ans=0;
for(int i=1;i<=n;i++){
if(!num[i]) dfs(i);
ans=max(ans,num[i]); //求最大值
}
printf("%d\n",ans);
}
return 0;
}