zoukankan      html  css  js  c++  java
  • 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
    "); 
    		else printf("%lld
    ",lct.p[i].val-Dij::d[i]);  
    	}
    	return 0; 
    }
    

      

  • 相关阅读:
    【WCF】授权策略详解
    【WCF】基址与默认终结点
    【Win 10 应用开发】手写识别
    【.net 深呼吸】连接Access数据库应注意的几点
    【WCF】自定义地址头的筛选器
    【Win 10 应用开发】InkToolBar——涂鸦如此简单
    【WCF】为终结点地址应用地址头
    【.net 深呼吸】EqualityComparer——自定义相等比较
    【.net 深呼吸】使用二进制格式来压缩XML文档
    PHP根据传入的经纬度,和距离范围,返回所有在距离范围内的经纬度的取值范围
  • 原文地址:https://www.cnblogs.com/guangheli/p/11671171.html
Copyright © 2011-2022 走看看