[树上LIS 线段树合并] Codeforces 490F #279 (Div. 2) F. Treeland Tour

这道题数据好小啊 那么就可以暴力DP了

这里有nlog2n的做法

我们想一条链可以在他的LCA处统计

每个点 我们对于以每个子树中的权值结尾的LIS LDS记录在线段树里

我们可以向上合并线段树 答案在合并的时候更新就好了

用 这一棵左儿子的lis和那一颗右儿子的lds 与 这一棵左儿子的lds和那一颗右儿子的lis 更新答案


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=200005;

struct edge{
  int u,v,next;
}G[N<<1];
int head[N],inum;

inline void add(int u,int v,int p){
  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

int root[N];
int ls[40*N],rs[40*N],lis[40*N],lds[40*N],ncnt;

int Ret;

inline void M(int& x,int y){
  if (!x || !y) { x=x+y; return; }
  lis[x]=max(lis[x],lis[y]);
  lds[x]=max(lds[x],lds[y]);
  Ret=max(Ret,max(lis[ls[x]]+lds[rs[y]],lds[rs[x]]+lis[ls[y]]));
  M(ls[x],ls[y]);
  M(rs[x],rs[y]);
}

inline void Modify(int &x,int l,int r,int t,int v,int *a){
  if (!x) x=++ncnt;
  a[x]=max(a[x],v);
  if (l==r) return; int mid=(l+r)>>1;
  if (t<=mid) Modify(ls[x],l,mid,t,v,a);
  else Modify(rs[x],mid+1,r,t,v,a);
}

inline int Query(int x,int l,int r,int ql,int qr,int *a){
  if (l>r) return 0;
  if (!x) return 0;
  if (ql<=l && r<=qr) return a[x];
  int ret=0,mid=(l+r)>>1;
  if (ql<=mid) ret=max(ret,Query(ls[x],l,mid,ql,qr,a));
  if (qr>mid) ret=max(ret,Query(rs[x],mid+1,r,ql,qr,a));
  return ret;
}

int sx[N],icnt;
inline int Bin(int x){
  return lower_bound(sx+1,sx+icnt+1,x)-sx;
}

int n,val[N];
int Ans;
#define V G[p].v
inline void dfs(int u,int fa){
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa)
      dfs(V,u);
  Ret=0;
  int nlis=0,nlds=0,ilis,ilds;
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa){
      	ilis=Query(root[V],1,icnt,1,val[u]-1,lis);
  		ilds=Query(root[V],1,icnt,val[u]+1,icnt,lds);
      M(root[u],root[V]);
    	Ans=max(Ans,ilis+1+nlds);
    	Ans=max(Ans,ilds+1+nlis);
    	nlis=max(nlis,ilis);
    	nlds=max(nlds,ilds);
  	}
  Ans=max(Ans,Ret);
  Modify(root[u],1,icnt,val[u],nlis+1,lis);
  Modify(root[u],1,icnt,val[u],nlds+1,lds);
}


int main(){
  int iu,iv;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); for (int i=1;i<=n;i++) read(val[i]),sx[++icnt]=val[i];
  sort(sx+1,sx+icnt+1);
  icnt=unique(sx+1,sx+icnt+1)-sx-1;
  for (int i=1;i<=n;i++) val[i]=Bin(val[i]);
  for (int i=1;i<n;i++)
    read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
  dfs(1,0);
  printf("%d\n",Ans);
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值