Divide by Zero 2018 and Codeforces Round #474 (Div. 1 + Div. 2, combined) F. Pathwalks(动态开点线段树)

题目

n(n<=1e5)个点,m(m<=1e5)条有向边的图,

有可能有重边自环,或图本身不连通,

依次输入m条边的u,v,w(第i条输入的边的路径号是i),

要求构造一条最长路径,使得这条路径中的路径号递增,且w是严格递增的

思路来源

https://blog.csdn.net/qq_39809664/article/details/79871282(map+BIT)

https://blog.csdn.net/white_elephant/article/details/80879562(线段树优化建图/主席树)

题解

这题做法很多,BB一个简易版本的主席树做法

自己手推一下,发现每个点都得开一棵线段树,当前u和上一个v接上

线段树应该维护两个值(w,num),对于当前W,要找到w<W中num最大的那一个,

所以,动态开点线段树,就满足了空间要求

(*)如果map+BIT,就是用map实现动态开点

(**)线段树优化建图还不会,咕了

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,root[N],cnt;
int ans,u,v,w,num;
//主席树动态开点思想 
struct node
{
	int l,r,mx;
	node():l(0),r(0),mx(0){}
}e[N*20];
void upd(int &p,int l,int r,int x,int v)
{
	if(!p)p=++cnt;
	if(l==r)
	{
		e[p].mx=max(e[p].mx,v);
		return;
	}
	int mid=(l+r)/2;
	if(x<=mid)upd(e[p].l,l,mid,x,v);
	else upd(e[p].r,mid+1,r,x,v);
	e[p].mx=max(e[e[p].l].mx,e[e[p].r].mx);	
}
int ask(int p,int l,int r,int ql,int qr)
{
	if(ql>qr)return 0;
	if(ql<=l&&r<=qr)return e[p].mx;
	int mid=(l+r)/2,ans=0;
	if(ql<=mid)ans=max(ans,ask(e[p].l,l,mid,ql,qr));
	if(qr>mid)ans=max(ans,ask(e[p].r,mid+1,r,ql,qr));
	return ans; 
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d%d",&u,&v,&w);
		num=ask(root[u],0,1e5,0,w-1);
		upd(root[v],0,1e5,w,num+1);
		ans=max(ans,num+1);
	}
	printf("%d\n",ans);
	return 0;
} 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值