习题:树上的最短路(树链剖分优化建图)

题目

下水道的主干路由n个节点和\(n-1\)条边所组成,每条边通过它都需要一个时间\(t_i\)这种边是双向的

下水道上有一些塌陷,我们用\((l_1,r_1,l_2,r_2,c)\)来描述,表示从\(l_1\)\(r_1\)路径上的点,到\(l_2\)\(r_2\)路径上的任意一个点所需要的时间为\(c\)注意塌陷是单向的

求每一个点到目标节点\(k\)的最快时间

思路

\(k\)转换\(k\)到每一个点,塌陷反过来建就好了

之后考虑塌陷

直接树链剖分暴力建图即可

代码

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<cstdio>
using namespace std;
void read(int &x)
{
	x=0;
	int f=1;
	char c=getchar();
	while('0'>c||c>'9')
	{
		if(c=='-')
			f=-1;
		c=getchar();
	}
	while('0'<=c&&c<='9')
	{
		x=(x<<3)+(x<<1)+c-'0';
		c=getchar();
	}
	x*=f;
}
void read(long long &x)
{
	x=0;
	int f=1;
	char c=getchar();
	while('0'>c||c>'9')
	{
		if(c=='-')
			f=-1;
		c=getchar();
	}
	while('0'<=c&&c<='9')
	{
		x=(x<<3)+(x<<1)+c-'0';
		c=getchar();
	}
	x*=f;
}
void write(long long x)
{
	if(x>9)
		write(x/10);
	putchar(x%10+'0');
}
struct node
{
	#define MAXN 250005
	struct node_tre
	{
		int l;
		int r;
	}tre[2][MAXN*4];
	struct node_g
	{
		int e;
		long long w;
		friend bool operator < (const node_g &a,const node_g &b)
		{
			return a.w>b.w;
		}
	};
	int n,m,s;
	int cnt;
	vector<node_g> tree[MAXN];
	vector<node_g> g[9*MAXN+100005*2];
	int id[MAXN];
	int wson[MAXN];
	int siz[MAXN];
	int ori[MAXN];
	int dep[MAXN];
	int top[MAXN];
	int fa[MAXN];
	long long dis[9*MAXN+100005*2];
	bool vis[9*MAXN+100005*2];
	priority_queue<node_g> q;
	#undef MAXN
	void add_edge(int u,int v,long long w)
	{
		tree[u].push_back((node_g){v,w});
	}
	void dfs1(int u,int fa)
	{
		int maxx=-1;
		siz[u]=1;
		dep[u]=dep[fa]+1;
		for(int i=0;i<tree[u].size();i++)
		{
			int v=tree[u][i].e;
			if(v!=fa)
			{
				dfs1(v,u);
				siz[u]+=siz[v];
				if(siz[v]>maxx)
				{
					maxx=siz[v];
					wson[u]=v;
				}
			}
		}
	}
	void dfs2(int u,int top_chain)
	{
		top[u]=top_chain;
		id[u]=++cnt;
		ori[cnt]=u;
		if(wson[u])
			dfs2(wson[u],top_chain);
		for(int i=0;i<tree[u].size();i++)
		{
			int v=tree[u][i].e;
			
			if(v!=wson[u]&&dep[v]==dep[u]+1)
			{
				fa[v]=u;
				dfs2(v,v);
			}
				
		}
	}
	void build(int l,int r,int k)
	{
		tre[0][k].l=tre[1][k].l=l;
		tre[0][k].r=tre[1][k].r=r;
		if(l==r)
		{
			g[l].push_back((node_g){n+k,0});
			g[5*n+k].push_back((node_g){l,0});
			return;
		}
		g[n+(k<<1)].push_back((node_g){n+k,0});
		g[n+(k<<1|1)].push_back((node_g){n+k,0});
		g[5*n+k].push_back((node_g){5*n+(k<<1),0});
		g[5*n+k].push_back((node_g){5*n+(k<<1|1),0});
		int mid=(l+r)>>1;
		build(l,mid,k<<1);
		build(mid+1,r,k<<1|1);
	}
	void init()
	{
		dfs1(1,0);
		dfs2(1,1);
		build(1,n,1);
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<tree[i].size();j++)
			{
				int v=tree[i][j].e;
				long long w=tree[i][j].w;
				g[id[i]].push_back((node_g){id[v],w});
				g[id[v]].push_back((node_g){id[i],w});
			}
		}
		cnt=9*n;
	}
	void change_tre(int l,int r,int id,int k,int opt)
	{
		if(l>tre[opt][k].r||tre[opt][k].l>r)
			return;
		if(l<=tre[opt][k].l&&tre[opt][k].r<=r)
		{
			if(opt==0)
				g[n+k].push_back((node_g){id,0});
			else
				g[id].push_back((node_g){5*n+k,0});
			return;
		}
		change_tre(l,r,id,k<<1,opt);
		change_tre(l,r,id,k<<1|1,opt);
	}
	void change(int x,int y,int st,int opt)
	{
		while(top[x]!=top[y])
		{
			if(dep[top[x]]>dep[top[y]])
				swap(x,y);
			change_tre(id[top[y]],id[y],st,1,opt);
			y=fa[top[y]];
		}
		if(dep[x]<dep[y])
			swap(x,y);
		change_tre(id[y],id[x],st,1,opt);
	}
	void link(int l1,int r1,int l2,int r2,long long w)
	{
		change(l1,r1,++cnt,0);
		change(l2,r2,++cnt,1);
		g[cnt-1].push_back((node_g){cnt,w});
	}
	void dij()
	{
		memset(dis,0x3f,sizeof(dis));
		q.push((node_g){id[s],0});
		dis[id[s]]=0;
		while(!q.empty())
		{
			node_g u=q.top();
			q.pop();
			if(vis[u.e])
				continue;
			vis[u.e]=1;
			for(int i=0;i<g[u.e].size();i++)
			{
				int v=g[u.e][i].e;
				long long w=g[u.e][i].w;
				if(dis[u.e]+w<dis[v])
				{
					dis[v]=w+dis[u.e];
					q.push((node_g){v,dis[v]});
				}
			}
		}
	}
	void pr()
	{
		for(int i=1;i<=n;i++)
		{
			write(dis[id[i]]);
			putchar('\n');
		}
	}
}tre;
int main()
{
	read(tre.n);
	read(tre.m);
	read(tre.s);
	for(int i=1,u,v;i<tre.n;i++)
	{
		long long w;
		read(u);
		read(v);
		read(w);
		tre.add_edge(u,v,w);
		tre.add_edge(v,u,w);
	}
	tre.init();
	for(int i=1,l1,r1,l2,r2;i<=tre.m;i++)
	{
		long long w;
		read(l1);
		read(r1);
		read(l2);
		read(r2);
		read(w);
		swap(l1,l2);
		swap(r1,r2);
		tre.link(l1,r1,l2,r2,w);
	}
	tre.dij();
	tre.pr();
	return 0;
}

posted @ 2020-01-28 11:21  loney_s  阅读(317)  评论(0)    收藏  举报