• 【刷题】BZOJ 2125 最短路


    Description

    给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。

    Input

    输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w 最后Q行,每行两个整数v,u表示一组询问

    Output

    输出Q行,每行一个整数表示询问的答案

    Sample Input

    9 10 2  
    1 2 1  
    1 4 1  
    3 4 1  
    2 3 1  
    3 7 1  
    7 8 2  
    7 9 2  
    1 5 3  
    1 6 4  
    5 6 1  
    1 9  
    5 7  
    

    Sample Output

    5  
    6  
    

    HINT

    对于100%的数据,N<=10000,Q<=10000

    Solution

    仙人掌上的最短路

    建圆方树,将原图变成树,求出每个点到根的最短距离,询问的话差分一下就好了,这是个经典差分

    但是求LCA的时候要分情况

    首先,如果LCA是圆点,即不在环上走,那么直接差分就好了

    如果LCA是方点,那么就会要在环上走,所以要找LCA下面的两个点,就是进入环的两个点,先求出询问的两个点到入环的两个点的距离,然后要找入环的两个点在环上短侧的距离。所以对于每个环即点双,要保存这个环的总长,以及每个点的前缀长,以便快速求环上两点的最短距离

    然后就做完了

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=10000+10,MAXM=1000000+10,inf=0x3f3f3f3f;
    int n,m,Q,e,to[MAXM<<1],nex[MAXM<<1],beg[MAXN],DFN[MAXN],LOW[MAXN],d[MAXN],dep[MAXN],Jie[20][MAXN],Visit_Num,sum[MAXN],len[MAXN],cnt,out[MAXM<<1],Be[MAXN],was[MAXM<<1],p[MAXN];
    std::stack<int> s;
    std::queue<int> q;
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y,int z=0)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	out[e]=x;
    	beg[x]=e;
    	was[e]=z;
    }
    inline void SPFA(int s)
    {
    	for(register int i=1;i<=n;++i)d[i]=inf;
    	d[s]=0;
    	p[s]=1;
    	q.push(s);
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		p[x]=0;
    		for(register int i=beg[x];i;i=nex[i])
    			if(d[to[i]]>d[x]+was[i])
    			{
    				d[to[i]]=d[x]+was[i];
    				if(!p[to[i]])p[to[i]]=1,q.push(to[i]);
    			}
    	}
    }
    inline void Tarjan(int x,int f)
    {
    	DFN[x]=LOW[x]=++Visit_Num;
    	for(register int i=beg[x];i;i=nex[i])
    		if(to[i]==f)continue;
    		else if(!DFN[to[i]])
    		{
    			s.push(i);
    			Tarjan(to[i],x);
    			chkmin(LOW[x],LOW[to[i]]);
    			if(LOW[to[i]]>=DFN[x])
    			{
    				int temp;++cnt;
    				do{
    					temp=s.top();
    					s.pop();
    					len[cnt]+=was[temp];
    					if(out[temp]!=x||to[temp]!=to[i])sum[out[temp]]=0;
    					sum[out[temp]]+=sum[to[temp]]+was[temp];
    					if(out[temp]!=x)
    					{
    						Jie[0][out[temp]]=x;
    						Be[out[temp]]=cnt;
    					}
    					if(to[temp]!=x)
    					{
    						Jie[0][to[temp]]=x;
    						if(to[temp]!=to[i])Be[to[temp]]=cnt;
    					}
    				}while(out[temp]!=x||to[temp]!=to[i]);
    			}
    		}
    		else if(DFN[to[i]]<DFN[x])s.push(i),chkmin(LOW[x],DFN[to[i]]);
    }
    inline void dfs(int x,int f)
    {
    	dep[x]=dep[f]+1;
    	for(register int i=beg[x];i;i=nex[i])
    		if(to[i]!=f)dfs(to[i],x);
    }
    inline int LCA(int u,int v,int &iu,int &iv)
    {
    	if(dep[u]<dep[v])std::swap(u,v);
    	iu=iv=v;
    	int tmp=dep[u]-dep[v];
    	if(dep[u]>dep[v])
    		for(register int i=19;i>=0;--i)
    			if(tmp>>i&1)u=Jie[i][u];
    	if(u==v)return u;
    	for(register int i=19;i>=0;--i)
    		if(Jie[i][u]^Jie[i][v])u=Jie[i][u],v=Jie[i][v];
    	iu=u,iv=v;
    	return Jie[0][u];
    }
    int main()
    {
    	read(n);read(m);read(Q);
    	for(register int i=1;i<=m;++i)
    	{
    		int u,v,w;read(u);read(v);read(w);
    		insert(u,v,w);insert(v,u,w);
    	}
    	SPFA(1);Tarjan(1,0);
    	e=0;memset(beg,0,sizeof(beg));
    	for(register int i=2;i<=n;++i)insert(i,Jie[0][i]),insert(Jie[0][i],i);
    	dfs(1,0);
    	for(register int j=1;j<=19;++j)
    		for(register int i=1;i<=n;++i)Jie[j][i]=Jie[j-1][Jie[j-1][i]];
    	while(Q--)
    	{
    		int u,v,iu,iv,lca,res=0;read(u);read(v);lca=LCA(u,v,iu,iv);
    		if(Be[iu]&&Be[iu]==Be[iv])
    		{
    			int l=std::abs(sum[iu]-sum[iv]),r=len[Be[iu]]-l;
    			res=d[u]+d[v]-d[iu]-d[iv]+min(l,r);
    		}
    		else res=d[u]+d[v]-(d[lca]<<1);
    		printf("%d
    ",res);
    	}
    	return 0;
    }
    
  • 相关阅读:
    javascript之全局函数
    讲真,MySQL索引优化看这篇文章就够了
    aws亚马逊磁盘扩展卷步骤
    google支付回调验证(备用)
    Linux TCP状态TIME_WAIT 过多的处理
    MySQL索引优化分析
    CSS使图片变模糊,亲测非常好用
    linux ss 命令用法说明
    php一行代码获取本周一,本周日,上周一,上周日,本月一日,本月最后一日,上月一日,上月最后一日日期
    有哪些你追了很多女生才明白的道理?
  • 原文地址:https://www.cnblogs.com/hongyj/p/9561437.html
Copyright © 2020-2023  润新知