zoukankan      html  css  js  c++  java
  • 【题解】道路相遇

    道路相遇

    ( ext{Solution:})

    题意就是对于 ((u,v)) 找有多少个必经点。

    必经边就很简单了,直接上边双缩点。这里我们用圆方树解决必经点问题。

    考虑到圆方树的性质:方点和圆点一定是相邻的,没有一个圆点连圆点,也没有一个方点连方点。

    而对于两点的必经点,就是这条路径上的割点个数,也就是方点个数。

    那方点个数不就恰好是路径长度除以 (2)(-1) 吗,然后加上题目要求的原来的两个点就完成了。

    注意这题卡常:一个是空间开大,一个是在 tarjan 的时候就进行建图,避免使用 vector ,还有注意空间别开小,这里提示空间开小导致了 MLE.

    还有,链一类的东西也是有圆方树的,每相邻两个点构成点双,并且除了度为 (1) 的节点都是割点,它们可以满足圆方相邻的树结构。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e6+10;
    int head[N],Head[N],tot,tto,n,m;
    struct E{int nxt,to;}e[N],edge[N<<1];
    inline void link(int x,int y,int w=0){
    	if(w){
    		edge[++tto]=(E){Head[x],y};
    		Head[x]=tto;
    		return;
    	}
    	e[++tot]=(E){head[x],y};
    	head[x]=tot;
    }
    int dfn[N],low[N],dfstime,top,st[N],dep[N],Q;
    int node,siz[N],son[N],ttop[N],pa[N];
    void dfs1(int x,int fa){
    	siz[x]=1;pa[x]=fa;
    	dep[x]=dep[fa]+1;
    	for(int i=Head[x];i;i=edge[i].nxt){
    		int j=edge[i].to;
    		if(j==fa)continue;
    		dfs1(j,x);
    		siz[x]+=siz[j];
    		if(siz[j]>siz[son[x]])son[x]=j;
    	}
    }
    void dfs2(int u,int t){
    	ttop[u]=t;
    	if(!son[u])return;
    	dfs2(son[u],t);
    	for(int i=Head[u];i;i=edge[i].nxt){
    		int j=edge[i].to;
    		if(j==son[u]||j==pa[u])continue;
    		dfs2(j,j);
    	}
    }
    inline void write(int x){
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    }
    inline int Min(int x,int y){return x<y?x:y;}
    void tarjan(int x,int root){
    	st[++top]=x;
    	low[x]=dfn[x]=++dfstime;
    	if(x==root&&!head[x]){
    		++node;
    		link(x,node,1);
    		link(node,x,1);
    		return;
    	}
    	int ch=0;
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		if(!dfn[j]){
    			ch++;
    			tarjan(j,root);
    			low[x]=Min(low[x],low[j]);
    			if(low[j]>=dfn[x]){
    				int vex=-1;
    				++node;
    				do{
    					vex=st[top--];
    					link(node,vex,1);
    					link(vex,node,1);
    				}while(vex!=j);
    				link(node,x,1);
    				link(x,node,1);
    			}
    		}
    		else low[x]=Min(low[x],dfn[j]);
    	}
    }
    int LCA(int x,int y){
    	while(ttop[x]!=ttop[y]){
    		if(dep[ttop[x]]<dep[ttop[y]])swap(x,y);
    		x=pa[ttop[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    inline int read(){
    	int s=0;
    	char ch=getchar();
    	while(!isdigit(ch))ch=getchar();
    	while(isdigit(ch)){
    		s=s*10-'0'+ch;
    		ch=getchar();
    	}
    	return s;
    }
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=m;++i){
    		int x=read(),y=read();
    		link(x,y);link(y,x);
    	}
    	node=n;
    	for(int i=1;i<=n;++i)if(!dfn[i])top=0,tarjan(i,i);
    	for(int i=1;i<=node;++i){
    		if(!dep[i]){
    			dfs1(i,0);
    			dfs2(i,i);
    		}
    	}
    	Q=read();
    	while(Q--){
    		int u=read(),v=read();
    		int L=LCA(u,v);
    		write((dep[u]+dep[v]-dep[L]-dep[L])/2+1);
    		putchar('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    自学软件测试获取学习资源途径有哪些?
    微信发红包-测试分析
    软件测试初级经验
    面试
    电商项目
    LoadRunner11的安装流程+破解+汉化+下载
    Oracle和Mysql操作上的一些区别
    Android模拟器,ADB命令
    logging
    heapq
  • 原文地址:https://www.cnblogs.com/h-lka/p/15312212.html
Copyright © 2011-2022 走看看