BZOJ 1576 树剖+LCT

题意:给定一张图,保证 $1$ 号点到其他所有点的最短路径是唯一的,求:对于点 $i$,不经过 $1$ 到 $i$ 最短路径上最后一条边的最短路.

题解:可以先建出最短路树,然后枚举每一条非树边.

对于一条非树边,影响的只是 $(u,lca)$,$(lca,v)$ 这些点的答案,然后你发现可以写成 $dep[a]-dep[u]+val[i]+dep[v]$

对于 $a$ 来说,第一项是固定的,后面的几项对于一个链来说都是相同的,所以直接用 $LCT$ 维护区间最小值就行了.

#include <bits/stdc++.h>        
#define N 100003 
#define M 200005 
#define ll long long                    
#define inf 1000000000000
#define inf2 10000000000 
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)    
using namespace std;            
ll output[N];     
vector<int>G[N]; 
int lst[N],from[N],n,m;          
namespace Dij     
{
	ll val[M<<1],d[N];     
	int hd[N],to[M<<1],nex[M<<1],done[N],edges,s;             
	struct Node 
	{
		int u; 
		ll dis;  
		Node(int u=0,ll dis=0):u(u),dis(dis){}  
		bool operator<(Node b) const { return b.dis<dis; }       
	};      
	priority_queue<Node>q;   
	void addedge(int u,int v,ll c) 
	{
		nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;    
	}
	void dijkstra() 
	{
		memset(d,0x3f,sizeof(d));    
		d[s]=0ll;   
		q.push(Node(s,0ll));   
		while(!q.empty()) 
		{ 
			Node e=q.top(); q.pop();   
			int u=e.u;  
			if(done[u]) continue;  
			done[u]=1;   
			for(int i=hd[u];i;i=nex[i]) 
			{ 
				int v=to[i];    
				if(d[u]+val[i]<d[v]) 
				{
					lst[v]=i;
					from[v]=u;                      
					d[v]=d[u]+val[i];
					q.push(Node(v, d[v]));    
				}
			}
		}
		for(int i=2;i<=n;++i) G[from[i]].push_back(i);       
	}
}   
namespace tree
{  
	int tim; 
	int size[N],dfn[N],top[N],dep[N],son[N],fa[N]; 
	void dfs1(int u,int ff) 
	{ 
		fa[u]=ff,size[u]=1,dep[u]=dep[ff]+1; 
		for(int i=0;i<G[u].size();++i)  
		{
		    dfs1(G[u][i],u);  
			size[u]+=size[G[u][i]]; 
			if(size[G[u][i]]>size[son[u]]) son[u]=G[u][i]; 
		}
	}    
	void dfs2(int u,int tp) 
	{
		top[u]=tp; 
		if(son[u]) dfs2(son[u], tp); 
		for(int i=0;i<G[u].size();++i) 
			if(G[u][i]!=son[u]) dfs2(G[u][i], G[u][i]);          
	}
	int LCA(int x,int y) 
	{
		while(top[x]!=top[y]) 
		{
			dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];  
		}
		return dep[x]<dep[y]?x:y;  
	}
};        
struct Link_Cut_Tree
{   
	#define lson p[x].ch[0] 
	#define rson p[x].ch[1] 
	int sta[N];  
	struct Node 
	{ 
		int ch[2],tag,f,rev; 
		ll minn,pu,val;  
	}p[N];   
	inline int get(int x) { return p[p[x].f].ch[1]==x; }
	inline int isrt(int x) { return !(p[p[x].f].ch[0]==x||p[p[x].f].ch[1]==x); }         
	inline void pushup(int x) 
	{ 
		p[x].minn=p[x].val; 
		if(lson) p[x].minn=min(p[x].minn, p[lson].minn); 
		if(rson) p[x].minn=min(p[x].minn, p[rson].minn);  
	}   
	void markrev(int x)
	{ 
		if(x) swap(lson,rson), p[x].rev^=1; 
	} 
	void marktag(int x,ll v) 
	{
		if(x) 
		{
			p[x].val=min(p[x].val,v);                    
			if(!p[x].tag || p[x].pu>v) p[x].pu=v, p[x].tag=1;      
			pushup(x);            
		}
	}
	void pushdown(int x)  
	{   
		if(!x) return; 
		if(p[x].tag) 
		{ 
			if(lson) marktag(lson, p[x].pu);  
			if(rson) marktag(rson, p[x].pu);  
			p[x].tag=0; 
		}
		if(p[x].rev) 
		{
			if(lson) markrev(lson); 
			if(rson) markrev(rson); 
			p[x].rev=0; 
		}
	}
	inline void rotate(int x) 
	{ 
		int old=p[x].f, fold=p[old].f, which=get(x);  
		if(!isrt(old)) p[fold].ch[p[fold].ch[1]==old]=x;   
		p[old].ch[which]=p[x].ch[which^1], p[p[old].ch[which]].f=old; 
		p[x].ch[which^1]=old, p[old].f=x, p[x].f=fold; 
		pushup(old), pushup(x); 
	}
	inline void splay(int x) 
	{ 
		int u=x,v=0,fa; 
		for(sta[++v]=u; !isrt(u); u=p[u].f) sta[++v]=p[u].f; 
		for(;v;--v) pushdown(sta[v]); 
		for(u=p[u].f;(fa=p[x].f)!=u;rotate(x)) 
		    if(p[fa].f!=u) 
				rotate(get(fa)==get(x)?fa:x);    
	}
	void Access(int x) 
	{
		for(int y=0;x;y=x,x=p[x].f) 
		    splay(x), rson=y, pushup(x);         
	} 
	void makeroot(int x) 
	{
		Access(x), splay(x), markrev(x); 
	} 
	void split(int x,int y) 
	{
		makeroot(x), Access(y), splay(y);    
	}
	int find(int x) 
	{ 
		for(pushdown(x); rson ; pushdown(x))  
		{  
			x=rson;     
		}
		return x;      
	}
	#undef lson 
	#undef rson 
}lct;         
void build_tree(int u,int ff) 
{
	lct.p[u].f=ff; 
	lct.p[u].val=inf;       
	lct.pushup(u); 
	for(int i=0;i<G[u].size();++i) build_tree(G[u][i], u); 
}
int main() 
{ 
	// setIO("input");       
	int i,j; 
	scanf("%d%d",&n,&m);     
	for(i=1;i<=m;++i) 
	{
		int u,v,c; 
		scanf("%d%d%d",&u,&v,&c);            
		Dij::addedge(u,v,1ll*c);    
		Dij::addedge(v,u,1ll*c);     
	}
	Dij::s=1;   
	Dij::dijkstra(); 
	tree::dfs1(1,0); 
	tree::dfs2(1,1);              
	build_tree(1,0);         
	for(i=1;i<=n;++i) 
	{
		for(j=Dij::hd[i];j;j=Dij::nex[j]) 
		{
			int v=Dij::to[j];  
			if(lst[v]==j) continue;        
			int lca=tree::LCA(i,v);       
			lct.split(v,lca);                      
			int pp=lct.find(lct.p[lca].ch[0]);                   
			if(pp) 
			{ 
				lct.split(v, pp);     
			    lct.marktag(pp, Dij::d[v]+Dij::d[i]+Dij::val[j]);     
			}
		}
	}     
	for(i=2;i<=n;++i) 
	{
		lct.Access(i); 
		lct.splay(i);  
		if(lct.p[i].val>=inf2) printf("-1\n"); 
		else printf("%lld\n",lct.p[i].val-Dij::d[i]);  
	}
	return 0; 
}

  

posted @ 2019-10-14 14:03  EM-LGH  阅读(112)  评论(0编辑  收藏  举报