【NOIP 模拟赛】改造二叉树 最长上升子序列

biubiu~~~

这道题我一眼就以为是线段树优化dp并且有了清晰的思路但是发现,我不会线段树区间平移,我以为只是我不会,然而根本就不行........

正解是把序列排出来然后我们让他们减去他们的下标之后求最长上升子序列。

#include <cstdio>
#include <algorithm>
const int N=100500;
int n,a[N],b[N],ch[N][2],len,pos[N],c[N],f[N];
void  dfs(int x){
  if(!x)return;
  dfs(ch[x][0]);
  b[++len]=a[x];
  dfs(ch[x][1]);
}
inline int Min(int x,int y){
  return x<y?x:y;
}
inline int Max(int x,int y){
  return x>y?x:y;
}
inline bool comp(int x,int y){
  return b[x]<b[y];
}
inline int get_Max(int x){
  int ret=0;
  while(x){
    ret=Max(ret,c[x]);
    x-=x&(-x);
  }
  return ret;
}
inline void ins(int x,int y){
  while(y<=len){
    c[y]=Max(x,c[y]);
    y+=y&(-y);
  }
}
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++)scanf("%d",&a[i]);
  for(int i=2,x,y;i<=n;i++){
    scanf("%d%d",&x,&y);
    ch[x][y]=i;
  }
  dfs(1);
  len=0;
  for(int i=1;i<=n;i++)
    b[i]-=i,pos[i]=i;
  std::sort(pos+1,pos+n+1,comp);
  for(int i=1,last;i<=n;i++){
    if(i==1||b[pos[i]]!=last)
      len++;
    last=b[pos[i]];
    b[pos[i]]=len;
  }
  int ans=0;
  for(int i=1;i<=n;i++){
    f[i]=get_Max(b[i])+1;
    ins(f[i],b[i]);
    ans=Max(ans,f[i]);
  }
  printf("%d",n-ans);
}

 

posted @ 2017-08-13 19:48  TS_Hugh  阅读(420)  评论(0编辑  收藏  举报