题目
题解
考虑链。
对于链,直接做一遍最长不下降子序列。
考虑菊花。同一个节点的不同的子树是不会互相影响的。
考虑如何构造最长不下降子序列。
f[i]
f
[
i
]
表示长度为
i
i
的不下降子序列的末尾的最小值。新加入一个元素,二分就好了。
思维变换:每个点维护一个set,表示
x
x
的子树要留下来的点的权值,假设作为数组的最后一个元素,即将加入
f
f
,那么是不是替换其中一个元素或者是将加入set?
心得
把f看做什么?
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define N 200010
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{
int to,next;
};note edge[N*2];
int tot,head[N];
int i,j,k,l,n,m,ans,wz;
int x,y;
int val[N],fa[N];
multiset<int>s[N];
multiset<int>::iterator u;
bool p;
int read(){
int rs=0,fh=1;char ch;
while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
return fh*rs;
}
void lb(int x,int y){edge[++tot].to=y;edge[tot].next=head[x];head[x]=tot;}
void merge(int x,int y){
if(s[x].size()>s[y].size())swap(s[x],s[y]);
for(u=s[x].begin();u!=s[x].end();u++)s[y].insert(*u);
s[x].clear();
}
void dg(int x){
int i;
for(i=head[x];i;i=edge[i].next){
if(fa[x]==edge[i].to)continue;
fa[edge[i].to]=x;
dg(edge[i].to);
merge(edge[i].to,x);
}
u=s[x].upper_bound(val[x]);
if(u!=s[x].end())s[x].erase(u);
s[x].insert(val[x]);
}
int main(){
freopen("simple.in","r",stdin);
freopen("simple.out","w",stdout);
n=read();
fo(i,1,n)val[i]=-read();
fo(i,1,n-1){
x=read();y=read();
lb(x,y);lb(y,x);
}
dg(1);
printf("%d",n-s[1].size());
return 0;
}