zoukankan      html  css  js  c++  java
  • 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;
    } 
    
  • 相关阅读:
    关于宏定义与内联函数
    vsv
    nginx与php之间的通信
    php高级
    PHP基础知识
    php结合redis实现高并发下的抢购、秒杀功能
    MySQL索引优化
    PHP基础(谈一谈Session&Cookie)
    Yii2框架查询指定字段和获取添加数据的id
    linux常用命令
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14668799.html
Copyright © 2011-2022 走看看