CF490F Treeland Tour

CF490F Treeland Tour

给出一棵带点权树,求树上最长上升子序列的长度。(这里指路径)

显然路径直接维护不好维护,于是我们可以考虑拆分,拆成一个点作为顶点的两条路径的拼接。

那么我们可以考虑使用值域线段树来维护当前子树中可以以每一个值作为结尾(或开头)的最长的子段和的大小。

两棵线段树分别维护 (LIS)(LDS) 对应值,然后处理子树完了直接线段树合并即可。

坑点是注意当前点不一定会成为序列上的一个点,而是当前点仅仅作为转弯的点的情况,这样的话我们需要在线段树合并的时候也更新答案即可。

代码:

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
    x=0;char ch=getchar();bool f=false;
    while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return ;
}
template <typename T>
inline void write(T x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10^48);
    return ;
}
const int N=2e5+5;
#define ll long long
int n,m,a[N],Idx,b[N],Ans;
int head[N],nex[N<<1],to[N<<1],idx;
inline void add(int u,int v){
	nex[++idx]=head[u];
	to[idx]=v;
	head[u]=idx;
	return ;
}
int root[N],ls[N<<5],rs[N<<5];
namespace LIS{
	int sum[N<<5],cur;
	void Modify(int &x,int l,int r,int pos,int v){
		if(!x) x=++cur;
		sum[x]=max(sum[x],v);
		if(l==r) return ;
		int mid=l+r>>1;
		if(pos<=mid) Modify(ls[x],l,mid,pos,v);
		else Modify(rs[x],mid+1,r,pos,v);
		return ;
	}
	int Query(int x,int l,int r,int ql,int qr){
		if(ql>qr||!x) return 0;
		if(ql<=l&&r<=qr) return sum[x];
		int res=0,mid=l+r>>1;
		if(ql<=mid) res=Query(ls[x],l,mid,ql,qr);
		if(qr>mid) res=max(res,Query(rs[x],mid+1,r,ql,qr));
		return res;
	}
}
namespace LDS{
	int sum[N<<5],cur;
	
	void Modify(int &x,int l,int r,int pos,int v){
		if(!x) x=++cur;
		sum[x]=max(sum[x],v);
		if(l==r) return ;
		int mid=l+r>>1;
		if(pos<=mid) Modify(ls[x],l,mid,pos,v);
		else Modify(rs[x],mid+1,r,pos,v);
		return ;
	}
	int Query(int x,int l,int r,int ql,int qr){
		if(ql>qr||!x) return 0;
		if(ql<=l&&r<=qr) return sum[x];
		int res=0,mid=l+r>>1;
		if(ql<=mid) res=Query(ls[x],l,mid,ql,qr);
		if(qr>mid) res=max(res,Query(rs[x],mid+1,r,ql,qr));
		return res;
	}
}
int Merge(int x,int y){
	if(!x||!y) return x+y;
	LDS::sum[x]=max(LDS::sum[x],LDS::sum[y]);
	LIS::sum[x]=max(LIS::sum[x],LIS::sum[y]);
	Ans=max(Ans,max(LIS::sum[ls[x]]+LDS::sum[rs[y]],LIS::sum[ls[y]]+LDS::sum[rs[x]]));
	ls[x]=Merge(ls[x],ls[y]);
	rs[x]=Merge(rs[x],rs[y]);
	return x;
}
void dfs(int x,int f){
	int U=0,D=0;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(y==f) continue;
		dfs(y,x);
		int nowu=LIS::Query(root[y],1,Idx,1,a[x]-1);
		int nowd=LDS::Query(root[y],1,Idx,a[x]+1,Idx);
		Ans=max(Ans,max(nowu+D+1,nowd+U+1));
		root[x]=Merge(root[x],root[y]);
		U=max(U,nowu),D=max(D,nowd);
	}
	LIS::Modify(root[x],1,Idx,a[x],U+1);
	LDS::Modify(root[x],1,Idx,a[x],D+1);
	return ;
}
signed main(){
	read(n);
	for(int i=1;i<=n;i++) read(a[i]),b[i]=a[i];
	sort(b+1,b+n+1);
	Idx=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+Idx+1,a[i])-b; 
	for(int i=1;i<n;i++){
		int u,v;read(u),read(v);
		add(u,v),add(v,u);
	}
	dfs(1,0);
	write(Ans);
	return 0;
} 
原文地址:https://www.cnblogs.com/Akmaey/p/14668799.html