给定带点权的无根树,求出所有简单路径上最长的LIS。
O(N²logn)的做法:
枚举每个节点作为根节点开始dfs,每条链上作一个nlogn的dp .
dp[i]表示长度为i的LIS结尾的最小值
当a[i]>dp[len],dp[++len] = a[i]
否则二分找到a[i]可以代替的位置
记得回溯的时候要恢复成原先的值。
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
#define lc rt<<1
#define rc rt<<1|1
const int maxn = 6e3 + 10;
const ll mod = 998244353;
const ll inf = (ll)4e17+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int a[maxn],n;
int dp[maxn],len;//长度为i的LIS 结尾元素最小值
vector<int> g[maxn];
int ans=1;//答案
void dfs(int rt,int fa)
{
for(int i:g[rt])
{
if(i==fa) continue;
if(a[i]>dp[len])
{
ans=max(ans,len+1);
dp[++len]=a[i];
dfs(i,rt);
len--;
}
else
{
int idx=lower_bound(dp+1,dp+len+1,a[i])-dp;//idx∈[1,len]
int v=dp[idx];
dp[idx]=a[i];
dfs(i,rt);
dp[idx]=v;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
}
for(int i=1,u,v;i<n;i++)
{
scanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
dp[1]=a[i];
len=1;
dfs(i,0);
}
cout<<ans<<'\n';
return 0;
}
贴一份n²logn的权值线段树tle的代码
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
#define lc rt<<1
#define rc rt<<1|1
const int maxn = 6e3 + 10;
const ll mod = 998244353;
const ll inf = (ll)4e17+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//对点权建树 维护以之结尾的最长的LIS
struct node
{
int mx;
int l,r;
}tree[maxn<<2];
inline void pushup(int rt)
{
tree[rt].mx=max(tree[lc].mx,tree[rc].mx);
}
inline void build(int rt,int l,int r)
{
tree[rt].mx=0;
tree[rt].l=l,tree[rt].r=r;
if(l==r) return;
else
{
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
}
inline void upd(int rt,int pos,int v,bool f)
{
int l=tree[rt].l,r=tree[rt].r;
if(l==r)
{
if(f)
tree[rt].mx=max(tree[rt].mx,v);
else tree[rt].mx=v;//直接赋值
return ;
}
int mid=l+r>>1;
if(pos<=mid) upd(lc,pos,v,f);
else upd(rc,pos,v,f);
pushup(rt);
}
inline int qry(int rt,int vl,int vr)
{
int l=tree[rt].l,r=tree[rt].r;
if(vl>vr) return 0;
if(vl<=l && r<=vr) return tree[rt].mx;
int mid=l+r>>1;
if(vr<=mid) return qry(lc,vl,vr);
else if(vl>mid) return qry(rc,vl,vr);
return max(qry(lc,vl,vr) , qry(rc,vl,vr));
}
int a[maxn];
vector<int> g[maxn];
int b[maxn],n0,n,idx[maxn];
int ans=1;//答案
void dfs(int rt,int fa)
{
for(int i:g[rt])
{
if(i==fa) continue;
int t=qry(1,1,idx[i]-1);//严格小于 所以是idx[i]-1
ans=max(ans,t+1);
int last=qry(1,idx[i],idx[i]);
upd(1,idx[i],t+1,1);
dfs(i,rt);
upd(1,idx[i],last,0);//回溯 消除影响变回之前的这个值
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
b[i]=a[i];
}
sort(b+1,b+n+1);
n0=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++) idx[i]=lower_bound(b+1,b+n0+1,a[i])-b;
for(int i=1,u,v;i<n;i++)
{
scanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
build(1,1,n0);
for(int i=1;i<=n;i++)
{
upd(1,idx[i],1,1);
dfs(i,i);
upd(1,idx[i],0,0);
}
cout<<ans<<'\n';
return 0;
}