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

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

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

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

代码

#include
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;
} 

 

你可能感兴趣的:(Divide by Zero 2018 and Codeforces Round #474 (Div. 1 + Div. 2, combined) F. Pathwalks(动态开点线段树))