zoukankan      html  css  js  c++  java
  • bzoj3047: Freda的传呼机&bzoj2125: 最短路

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3047

    http://www.lydsy.com/JudgeOnline/problem.php?id=2125

    双倍经验题

    题意很简单,求仙人掌两点间距离

    各种情况讨论了我一天多...

    在膜拜了一种新的建图方式后终于思路清晰了

    思路:首先树上的很好搞,dis[x]+dis[y]-2*dis[lca(x,y)]

    先用SPFA求出1号点到任意点的距离dis[x],这个待会求答案时要用

    仙人掌也是一种植物,所以我们要把他变成一棵树

    dfs时把每个简单环取出,每个环总有一个dfn最小的点,把它记做这个环的根

    把所有环上的点向环根连边,记录它属于哪个环bel[x](根不记录,因为它还有可能是另一个环的节点),顺便求出环的长度

    环边去掉,其他边不变,这就形成了一棵树



    这棵树有什么用呢?

    首先这棵树上的点没有变,只是边较原仙人掌有所变化

    那么我们就可以求任意两点x,y,的lca了

    接下来就是愉悦的分类讨论了

    设dep[x]>dep[y]

    分别记录x和y的祖先且是lca的儿子的点fx和fy


    1.x和y中一个是lca

    画图可知这个lca是不是原图的环都没有关系

    直接return dis[x]-dis[y]


    2.fx和fy都在同一个环上

    即bel[x]!=0&&bel[x]==bel[y]

    那么ans=dis[x]-dis[fx]+dis[y]-dis[fy]+d,d是fx,和fy在环上的距离

    这个画图也能知道

    d怎么求,可以在dfs时得到每个点的另一个距离rdis,这个rdis不是到1的最小距离,而是每个环都按一个方向走的距离

    或者你可以在取环的时候顺便求出环上点到环根的一个方向的距离rdis,这种更好理解一些,虽然我脑子一抽用了上一种方法

    这样就满足可减了,可以直接用abs(rdis[fx]-rdis[fy])得出fx和fy在环上的一段距离,用len[bel[fx]]-d可得另一种距离,取min即可


    3.fx和fy有一个不在环上或x和y不在同一个环上

    这个简单,画图即可 ans=dis[x]+dis[y]-dis[lca]*2


    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define abs(a) (a>0?a:(-(a)))
    const int maxn=50010,maxm=100010,maxk=22;
    using namespace std;
    int n,m,Q,dis[maxn],head,tail,q[maxm+10],sta[maxn],top,rdis[maxn],rcnt,fa[maxn][maxk],dfn[maxn],last[maxn],bel[maxn],rlen[maxn],dep[maxn];
    int pre[maxm],now[maxn],son[maxm],val[maxn],tot,tim;bool bo[maxn],del[maxm],vis[maxn];
    void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    void ins(int a,int b,int c){add(a,b,c),add(b,a,c);}
    void spfa(){
    	memset(dis,63,sizeof(dis));
    	head=dis[1]=0,q[tail=1]=1,bo[1]=1;
    	while (head<=tail){
    		if (++head>maxm) head=1;
    		int x=q[head];
    		for (int y=now[x];y;y=pre[y]){
    			if (dis[son[y]]>dis[x]+val[y]){
    				dis[son[y]]=dis[x]+val[y];
    				if (!bo[son[y]]){
    					if (++tail>maxm) tail=1;
    					q[tail]=son[y],bo[son[y]]=1;
    				}
    			}
    		}
    		bo[x]=0;
    	}
    }
    
    void getring(int st,int ed,int id){
    	del[id]=del[id^1]=1,rlen[++rcnt]+=val[id];
    	for (int x=ed;x!=st;x=son[last[x]^1]){
    		bel[x]=rcnt,del[last[x]]=del[last[x]^1]=1;
    		ins(st,x,0),rlen[rcnt]+=val[last[x]];
    	}
    }
    
    void dfs(int x){
    	dfn[x]=++tim;
    	for (int y=now[x];y;y=pre[y]) if (y!=(last[x]^1)&&(y<=(m*2+1))){
    		if (!dfn[son[y]]) last[son[y]]=y,rdis[son[y]]=rdis[x]+val[y],dfs(son[y]);
    		else if (dfn[son[y]]<dfn[x]) getring(son[y],x,y);
    	}
    }
    
    void dfs2(int x){
    	vis[x]=1;
    	for (int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    	for (int y=now[x];y;y=pre[y]) if (!del[y]&&son[y]!=fa[x][0])
    		dep[son[y]]=dep[x]+1,fa[son[y]][0]=x,dfs2(son[y]);
    }
    
    int query(int x,int y){
    	if (dep[x]<dep[y]) swap(x,y);
    	//printf("step1: %d %d
    ",x,y);
    	int a=x,b=y;
    	for (int h=dep[x]-dep[y],i=18;h&&i>=0;i--) if (h&(1<<i)) h-=(1<<i),x=fa[x][i];
    	//printf("step2: %d %d
    ",x,y);
    	if (x==y) return dis[a]-dis[b];//puts("cas1:链 "),
    	for (int i=18;i>=0;i--)
    		if (fa[x][i]!=fa[y][i])
    			x=fa[x][i],y=fa[y][i];
    	int lca=fa[x][0];
    	//if (!x||!y||!lca) return 0;
    	if (bel[x]&&bel[x]==bel[y]){
    		//puts("cas2:相同的环  ");
    		int d=abs(rdis[x]-rdis[y]);d=min(d,rlen[bel[x]]-d);
    		return dis[a]+dis[b]-dis[x]-dis[y]+d;
    	}
    	//puts("cas3:不同的环或不是环  ");
    	return dis[a]+dis[b]-2*dis[lca];
    }
    
    int main(){
    	scanf("%d%d%d",&n,&m,&Q),tot=1;
    	for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),ins(x,y,z);
    	spfa(),last[1]=-1,dfs(1),dfs2(1);
    	for (int i=1,x,y;i<=Q;i++) scanf("%d%d",&x,&y),printf("%d
    ",query(x,y));
    	return 0;
    }
    
    /*
    13 18 3
    1 2 5
    
    2 14 3
    2 9 5
    14 9 2
    
    9 15 4
    9 10 6
    15 10 3
    
    10 11 7
    11 12 6
    12 13 5
    13 10 4
    
    2 3 2
    3 4 3
    4 5 2
    5 6 3
    6 7 2
    7 8 3
    8 3 2
    
    15 12
    13 2
    15 12
    */


  • 相关阅读:
    PATA 1071 Speech Patterns.
    PATA 1027 Colors In Mars
    PATB 1038. 统计同成绩学生(20)
    1036. 跟奥巴马一起编程(15)
    PATA 1036. Boys vs Girls (25)
    PATA 1006. Sign In and Sign Out (25)
    读取web工程目录之外的图片并显示
    DOS命令
    java连接oracle集群
    servlet
  • 原文地址:https://www.cnblogs.com/thythy/p/5493478.html
Copyright © 2011-2022 走看看