F. Treeland Tour
题意:n个城市组成树型结构,每个城市有一定的人口。现在乐队沿一条不重复的路径去表演,需要每次表演时当前城市人口数量严格递增(不一定经过的所有城市都表演)。
思路:dp(树上LIS)。其实这题就是把两个算法结合起来,一个是树的dfs遍历,一个是最长递增子序列O(n*log(n))算法,是一道好题。具体解法就是在dfs的同时,对每一条dfs路径求LIS,注意现场的还原。。
#include<iostream>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
#define maxn 6010
int r[maxn]; //人口
vector<int> E[maxn]; //邻接表
int siz[maxn]; //点的度
int dp[maxn]; //dp求LIS
int least[maxn]; //保存每个长度尾巴的最小值
bool check[maxn]; //预处理,排除明显不能作为起点的点
int ans;
//深搜每条路径的同时,求出LIS
void fun(int x,int pre){
ans=max(ans,dp[x]);
for(int i=0;i<siz[x];i++){
int& cur=E[x][i];
if(cur==pre)continue;
int fnd=lower_bound(least+1,least+maxn,r[cur])-least;
dp[cur]=fnd;
int tmp=least[fnd];
least[fnd]=min(least[fnd],r[cur]);
fun(cur,x);
least[fnd]=tmp;
}
}
//预处理,排除明显不能作为起点的点
int dfs(int x){
int re=x;
for(int i=0;i<siz[x];i++){
if(r[E[x][i]]<r[x]){
re=dfs(E[x][i]);
}
}
check[re]=1;
return re;
}
int main(){
int n;
while(cin>>n){
ans=0;
fill(least,least+maxn,1000000000);
for(int i=1;i<=n;i++){
scanf("%d",&r[i]);
}
int u,v;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
siz[u]++; siz[v]++;
E[u].push_back(v);
E[v].push_back(u);
}
//预处理
for(int i=1;i<=n;i++)dfs(i);
for(int i=1;i<=n;i++){
if(!check[i])continue;
dp[i]=1;
least[1]=r[i];
fun(i,0);
}
cout<<ans<<endl;
}
return 0;
}