zoukankan      html  css  js  c++  java
  • [bzoj2125] 最短路

    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
    

    Solution

    无脑建圆方树,大力出奇迹。

    圆点和圆点的边权就直接是原图上的边权;

    圆点和方点的边权设为圆点和这个环上(dep)最小的点的最短距离。

    对于两个点((x,y)),设他们在圆方树上的(lca)(t),若(t)是圆点,就直接树上距离就好了。

    否则, 少跳一步,先跳掉离方点最近的两个圆点,然后在原图上求环上最小距离就好了。

    (萌新刚学OI,代码写的很丑,不要介意)

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 2e5+10;
    
    int n,m,q,cnt;
    int head[maxn],tot=1,dfn[maxn],dfn_cnt,f[maxn],mark[maxn],fr[maxn],bel[maxn],dis[maxn];
    struct edge{int to,nxt,w;}e[maxn<<1];
    
    void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
    void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
    
    int st[maxn],ed[maxn],val[maxn];
    
    void dfs(int x,int fa) {
    	dfn[x]=++dfn_cnt,f[x]=fa;
    	for(int i=head[x];i;i=e[i].nxt)
    		if(e[i].to!=fa) {
    			if(!dfn[e[i].to])
    				dis[e[i].to]=dis[x]+e[i].w,fr[e[i].to]=i,dfs(e[i].to,x);
    			else if(dfn[e[i].to]<dfn[x]) {
    				cnt++;int v=e[i].to;st[cnt]=e[i].to,ed[cnt]=x,val[cnt]=e[i].w;
    				ins(v,cnt,0),mark[i]=mark[i^1]=1;
    				int t=x;
    				while(t!=v) {
    					mark[fr[t]]=mark[fr[t]^1]=1;
    					ins(t,cnt,min(dis[t]-dis[v],dis[x]-dis[t]+e[i].w));
    					t=f[t];
    				}
    			}
    		}
    }
    
    int w[maxn][20],dep[maxn],d[maxn];
    
    void dfs2(int x,int fa) {
    	w[x][0]=fa,dep[x]=dep[fa]+1;
    	for(int i=1;i<=19;i++) w[x][i]=w[w[x][i-1]][i-1];
    	for(int i=head[x];i;i=e[i].nxt)
    		if(e[i].to!=fa&&!mark[i]) d[e[i].to]=d[x]+e[i].w,dfs2(e[i].to,x);
    }
    
    int lca(int x,int y) {
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int i=19;~i;i--) if(dep[w[x][i]]>=dep[y]) x=w[x][i];
    	if(x==y) return x;
    	for(int i=19;~i;i--) if(w[x][i]!=w[y][i]) x=w[x][i],y=w[y][i];
    	return w[x][0];
    }
    
    int approach(int x,int t) {
    	for(int i=19;~i;i--) if(dep[w[x][i]]>dep[t]) x=w[x][i];
    	return x;
    }
    
    int main() {
    	read(n),read(m),read(q);cnt=n;
    	for(int i=1,x,y,z;i<=m;i++) read(x),read(y),read(z),ins(x,y,z);
    	dfs(1,0),dfs2(1,0);
    	for(int i=1;i<=q;i++) {
    		int x,y;read(x),read(y);
    		int t=lca(x,y);
    		if(t<=n) {write(d[x]+d[y]-2*d[t]);continue;}
    		int xx=approach(x,t),yy=approach(y,t);
    		int ans=d[x]-d[xx]+d[y]-d[yy];
    		if(dis[xx]<dis[yy]) swap(xx,yy);
    		ans+=min(dis[xx]-dis[yy],dis[yy]-dis[st[t]]+dis[ed[t]]-dis[xx]+val[t]);
    		write(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    【bzoj1704】[Usaco2007 Mar]Face The Right Way 自动转身机 贪心
    【poj2104】K-th Number 主席树
    【bzoj3772】精神污染 STL+LCA+主席树
    【bzoj3932】[CQOI2015]任务查询系统 离散化+主席树
    【bzoj3545/bzoj3551】[ONTAK2010]Peaks/加强版 Kruskal+树上倍增+Dfs序+主席树
    【bzoj3524】[Poi2014]Couriers 主席树
    【bzoj2223】[Coci 2009]PATULJCI 主席树
    【bzoj2588】Spoj 10628. Count on a tree 离散化+主席树
    【bzoj1901】Zju2112 Dynamic Rankings 离散化+主席树+树状数组
    【bzoj1552】[Cerc2007]robotic sort Splay
  • 原文地址:https://www.cnblogs.com/hbyer/p/10273033.html
Copyright © 2011-2022 走看看