• [JZOJ5465]道路重建--边双缩点+树的直径


    题目链接

    lueluelue

    分析

    这鬼题卡了我10发提交,之前做过一道类似的题目:https://rye-catcher.github.io/2018/07/09/luogu题解P2860-USACO冗杂路径-缩点-桥/

    危险的边就是桥边,Tarjan求出边双后缩点整个图变成树,树边都是危险的边,我们需要加一条边构成一个新的ecc使危险的边最小

    于是一开始naiive的以为求出所有叶子节点判一判就好了,于是WA*1

    发现这个SB思路一看就是错的,又想到APIO 巡逻很像这道题,发现我们只要将树的直径两端点连起来一定是最优的,因为直径上的边都成为联通分量上的了就不是危险的边

    于是求个树的直径就好了

    结果发现求树的直径过程中会遍历一个环wtf?!虽然不知道为什么会有个环但加上个vis数组就没事了 WA*2

    接着交一发95 最后一点 RE 了,这时候才发现边的范围1e6

    改了一下又交了一发结果5分只过了最后一个点wtf?! 又是fread的锅 (NOIP都不敢用了)

    然后终于A了这题...

    代码

    /*
      code by RyeCatcher
    */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cctype>
    #include <utility>
    #include <queue>
    #include <vector>
    #include <ext/pb_ds/hash_policy.hpp>
    #include <ext/pb_ds/assoc_container.hpp>
    #include <iostream>
    #define DEBUG freopen("dat.in","r",stdin);freopen("wa.out","w",stdout);
    #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
    #define ri register int
    #define ll long long
    #define ull unsigned long long
    #define SIZE 1<<22
    using std::min;
    using std::max;
    using std::priority_queue;
    using std::queue;
    using std::vector;
    using std::pair;
    using namespace __gnu_pbds;
    inline char gc(){
        static char buf[SIZE],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
    }
    template <class T>inline void read(T &x){
        x=0;int ne=0;char c;
        while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
        while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
    }
    const int maxn=400005;
    const int M=4000005;
    const int inf=0x7fffffff;
    struct Edge{
    	int ne,to;
    }edge[M<<1];
    int h[maxn],num_edge=1;
    inline void add_edge(int f,int to){
    	edge[++num_edge].ne=h[f];
    	edge[num_edge].to=to;
    	h[f]=num_edge;
    }
    struct QAQ{
    	int ne,to;
    }se[M<<1];
    int sh[maxn],num_se=1;
    inline void add_se(int f,int to){
    	se[++num_se].ne=sh[f];
    	se[num_se].to=to;
    	sh[f]=num_se;
    }
    int n,m;
    int dfn[maxn],low[maxn],tot=0;
    bool bri[M<<1];
    int in_ecc[maxn],cnt=0;
    void tarjan(int now,int id){
    	int v;
    	dfn[now]=low[now]=++tot;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(!dfn[v]){
    			tarjan(v,i);
    			low[now]=min(low[now],low[v]);
    			if(dfn[now]<low[v]){
    				bri[i]=bri[i^1]=1;
    			}
    		}
    		else if(id!=(i^1)){
    			low[now]=min(low[now],dfn[v]);
    		}
    	}
    	return;
    }
    bool vis[maxn];
    void color(int now,int fa){
    	int v;
    	in_ecc[now]=cnt;
    	for(ri i=h[now];i;i=edge[i].ne){
    		v=edge[i].to;
    		if(bri[i]||in_ecc[v])continue;
    		color(v,now);
    	}
    }
    int rt,tmp;
    void dfs1(int now,int fa,int dis){
    	int v;
    	vis[now]=1;
    	if(dis>tmp){
    		rt=now,tmp=dis;
    	}
    	for(ri i=sh[now];i;i=se[i].ne){
    		v=se[i].to;
    		if(v==fa||vis[v])continue;
    		dfs1(v,now,dis+1);
    	}
    	return ;
    }
    int main(){
    	int x,y;
    	FO(rebuild);
    	//freopen("rebuild01.in","r",stdin);
    	//freopen("rebuild01.ans","w",stdout);
    	while(scanf("%d %d",&n,&m)!=EOF&&(n+m)){
    		//printf("--%d %d--
    ",n,m);
    		int S1=sizeof(bool)*(n+3),S2=sizeof(bool)*(m*2+3);
    		for(ri i=1;i<=n;i++){
    			h[i]=dfn[i]=sh[i]=in_ecc[i]=vis[i]=0;
    		}
    		memset(bri,0,S2);//清空桥边标记!!! 
    		num_edge=num_se=1;
    		tot=cnt=0;
    		for(ri i=1;i<=m;i++){
    			read(x),read(y);
    			add_edge(x,y),add_edge(y,x);
    		}
    		for(ri i=1;i<=n;i++)if(!dfn[i])tarjan(i,0);
    		for(ri i=1;i<=n;i++)if(!in_ecc[i]){
    			cnt++;
    			color(i,0);
    		}
    		//printf("%d
    ",cnt);
    		for(ri i=1;i<=n;i++){
    			x=in_ecc[i];
    			for(ri j=h[i];j;j=edge[j].ne){
    				y=in_ecc[edge[j].to];
    				if(x!=y){
    					add_se(x,y);
    					add_se(y,x);
    				}
    			}
    		}
    		rt=1,tmp=-1;
    		dfs1(1,0,0);
    		memset(vis,0,S1);
    		dfs1(rt,0,0);
    		//printf("%d
    ",lef);
    		printf("%d
    ",cnt-1-tmp);
    		//puts("wtf");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    五分钟上手Markdown
    css中居中方法小结
    事务和同步锁
    插入排序
    插入排序
    交换排序
    eclipse 常用快捷键
    交换排序
    二叉搜索树(BST)
    二叉树遍历以及根据前序遍历序列反向生成二叉树
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9824384.html
Copyright © 2020-2023  润新知