动态处理 减少搜索维度 960F

https://vjudge.net/problem/1476682/origin

这个东西是给个图,每条边带有一个id(id各不相等),每个边带有一个权值,求最长路径,路径上的权值递增,id递增

嗯~~刚开始不知道咋做,权值+id 好像也不太好dp

后来知道,要动态处理,例如把边按从大到小处理,

那么利用dp[i]表示从i开始的最长路径的长,注意,由于id是从大到小的

所以每取一条边{from,to,v,id},能够更新的只有dp[from]这样更新的复杂度就可以降到最低,

代码:

//Problem:
//Date:
//Skill:
//Bug:
/Definations/
//循环控制
#define CLR(a) memset((a),0,sizeof(a))
#define F(i,a,b) for(int i=a;i<=int(b);++i)
#define F2(i,a,b) for(int i=a;i>=int(b);--i)
#define RE(i,n)  for(int i=0;i<int(n);i++)
#define RE2(i,n) for(int i=1;i<=int(n);i++)
//输入输出
//#define INC(c) do{scanf("%c",&c);}while(isspace(c))
//#define ON cout<<endl
#define PII pair<int,int>
using namespace std;
const int inf = 0x3f3f3f3f;
const long long llinf = 0x3f3f3f3f3f3f3f3f;
Options//
typedef long long ll;
#define stdcpph
#define CPP_IO

#ifdef stdcpph
#include<bits/stdc++.h>
#else
#include<ctype.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<algorithm>
#include<functional>
#ifdef CPP_IO
#include<iostream>
#include<iomanip>
#include<string>
#else
#include<stdio.h>
#endif
#endif
Basic Functions//
template<typename INint>
inline void IN(INint &x)
{
	x = 0; int f = 1; char c; cin.get(c);
	while (c<'0' || c>'9') { if (c == '-')f = -1; cin.get(c); }
	while (c >= '0'&&c <= '9') { x = x * 10 + c - '0'; cin.get(c); }
	x *= f;
}
template<typename INint>
inline void OUT(INint x)
{
	if (x > 9)OUT(x / 10);
	cout.put(x % 10 + '0');
}
Added Functions//
const int maxn = int(1e5+4);
struct Edge
{
	int v;
	int id, w;
	bool operator<(const Edge b)const
	{
		//return id < b.id&&w < b.w;
		return id < b.id;
	}
};
set<Edge>G[maxn];
vector<int>es;
map<int,int> dp[maxn];//从i号结点开始,第一条边长为j的最长长度

int get( int v, int w)//从v开始 ,第一条边长>w的  路径长度
{
	int ret;
	auto it = dp[v].upper_bound( w);//获取大于w的边
	if (it == dp[v].end())ret = 0;
	else ret = it->second;

	return ret ;

}


Code/
int main()
{
	//freopen("C:\\Users\\VULCAN\\Desktop\\data.in", "r", stdin);
	int T(1), times(0);
#ifdef CPP_IO// CPP_IO
	std::ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	//cin >> T;
#else
	//IN(T);
#endif
	/
	while (++times, T--)
	{
		//memset(dp, -1, sizeof(dp));
		int n, m; cin >> n >> m;
		RE2(i, m)
		{
			int u, v, w;
			IN(u); IN(v); IN(w);
			es.push_back(u); es.push_back(v); es.push_back(w);
			//G[u].push_back({ v,i,w });
		}
		ll ans(0);
		for(int i=m;i>=1;i--)
		{
			int u, v, w;
			w = es[i * 3 - 1]; v = es[i * 3 - 2]; u = es[i * 3 - 3];
			int id = i;
			//G[u].insert({ v,id,w });

			int bui = get(v, w)+1;//从v开始的,第一边为w的,最长路径长

			int ori = get(u, w - 1);//从u开始的>=w的最佳长度
			if (bui<=ori)
				continue;
			else
			{
				dp[u][w] = bui;
				auto it = dp[u].lower_bound(w);//从u开始的,第一边长>w的
				while (it!=dp[u].begin())//没有边或者,路径长大于
				{
					--it;
					if (it->second > bui)
						continue;
					else
						it= dp[u].erase(it);
				}
			}
			ans = max(ans, (ll)bui);
		}

		cout << ans << endl;
	}
	///
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值