[ABC335E] Non-Decreasing Colorful Path

题意简述

给定一个 n n n 个点 m m m 条边的无向图,每个点有一个点权 a i a_i ai。对于每条从 1 1 1 n n n 的简单路径,路径的美丽值定义如下:

∙ \bullet 令序列 s s s 为按顺序走过的点的点权构成的序列。

∙ \bullet s s s 不是单调不下降序列,该路径美丽值为 0 0 0。否则,该路径美丽值为 s s s 中不同元素的个数。

输出 1 1 1 n n n 的简单路径中美丽值最大为多少。

解题思路

首先按照点权排序。排序完之后,对于第 i i i 个点,我们只需要从它前面找小于它的点转移。但是我们不太好处理点权相同的点。如何解决?当点权为 x x x 的点全部转移完之后,再 dfs 跑一遍点权为 x x x 的点,取其中的最大值进行转移即可。总的时间复杂度应该是 Θ ( n ) \Theta(n) Θ(n),但是常数较大。

代码示例

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,dp[200010],num=0,vis[200010]={0},b[200010];
struct node{
	int u,num;
	bool operator<(const node &b)const{
		return num<b.num;
	}
}a[200010];
vector<int> G[200010];
set<int> s;
void dfs(int x){
	s.insert(x);
    //将遍历的点存进来
	num=max(num,dp[x]);
    //取最大值
	vis[x]=1;
	for(int v:G[x]) if(!vis[v]&&b[v]==b[x]) dfs(v);
    //注意,只扫和当前点点权相同的点
}
signed main(){
	memset(dp,-0x3f,sizeof(dp));
    //初始化不能为0,否则转移会出问题
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i].num,a[i].u=i,b[i]=a[i].num;
    //b数组存储了每个点的点权
    //因为a数组排序后会打乱,所以b数组方便后续使用
	sort(a+1,a+n+1);
    //按点权排序
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dp[1]=1;
    //1号点出发
	for(int i=1;i<=n;i++){
		for(int v:G[a[i].u]){
			if(a[i].num>b[v]) dp[a[i].u]=max(dp[a[i].u],dp[v]+1);
			if(a[i].num==b[v]) dp[a[i].u]=max(dp[a[i].u],dp[v]);	
		}
        //扫一遍跟它相邻的点,进行更新
		if(a[i].num!=a[i+1].num||i==n){
        //如果当前点的点权和下一个点不同,说明点权和当前点点权相同的点全部更新完毕
        //可以进行一次总转移了
			int j=i;
			while(a[j].num==a[i].num&&j>=1){
            //扫所有的点权和当前点相同的点
				if(!vis[a[j].u]){
					s.clear();
					num=-0x3f3f3f3f3f3f3f3f;
					dfs(a[j].u);
                    //找其中的最大值
					for(int v:s) dp[v]=num;
                    //赋值
				}
				j--;
			}
		}
	}
	cout<<(dp[n]<0?0:dp[n])<<endl;
	return 0;
}
  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值