zoukankan      html  css  js  c++  java
  • P3304 [SDOI2013]直径(【模板】树直径的必经边)

    题目地址


    基本思路:

    • 题目要求树直径的必经边,那么首先应当获取一条直径.
    • 获取直径后从直径上的两个端点分别遍历一次直径,每次遍历直径时从直径上的每个点分别dfs一次并不经过直径上的点,如果深度可以被替换则说明非必经边.

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int MAXN=2e5+10,MAXM=MAXN*2;
    struct Edge{
    	ll from,to,w,nxt;
    }e[MAXM];
    int head[MAXN],edgeCnt=1;
    void addEdge(ll u,ll v,ll w){
    	e[++edgeCnt].from=u;
    	e[edgeCnt].to=v;
    	e[edgeCnt].w=w;
    	e[edgeCnt].nxt=head[u];
    	head[u]=edgeCnt;
    }
    ll dep[MAXN];
    bool vis[MAXN];
    int n;
    int from[MAXN];
    bool inDiameter[MAXN];//是否在直径上 
    ll st,ed;//直径端点 
    void markDiameter(){//标记直径 
    	int tmp=ed;
    	while(tmp){
    		inDiameter[tmp]=1;
    		tmp=from[tmp];
    	}
    }
    ll bfs(int s){//求直径 
    	memset(dep,0,sizeof(dep));
    	memset(vis,0,sizeof(vis));
    	memset(from,0,sizeof(from));
    	queue<int> q;
    	q.push(s);
    	vis[s]=1;
    	while(!q.empty()){
    		int nowU=q.front();
    		q.pop();
    		for(int i=head[nowU];i;i=e[i].nxt){
    			int nowV=e[i].to;
    			if(!vis[nowV]){
    				dep[nowV]=dep[nowU]+e[i].w;
    				vis[nowV]=1;
    				from[nowV]=nowU;
    				q.push(nowV);
    			}
    		}
    	}
    	ll ans=0,ansDep=0;
    	for(int i=1;i<=n;i++){
    		if(dep[i]>ansDep){
    			ans=i,ansDep=dep[i];
    		}
    	}
    	return ans;
    }
    ll dis_fromST[MAXN];//每个点到直径st端点的距离 
    bool vis_getDisFromST[MAXN];
    void bfs_getDisFromST(){
    	queue<int> q;
    	q.push(st);
    	vis_getDisFromST[st]=1;
    	while(!q.empty()){
    		int nowU=q.front();
    		q.pop();
    		for(int i=head[nowU];i;i=e[i].nxt){
    			int nowV=e[i].to;
    			if(!vis_getDisFromST[nowV]){
    				vis_getDisFromST[nowV]=1;
    				dis_fromST[nowV]=dis_fromST[nowU]+e[i].w;
    				q.push(nowV);
    			}
    		}
    	}
    }
    ll dis_fromED[MAXN];//每个点到直径ed端点的距离 
    bool vis_getDisFromED[MAXN];
    void bfs_getDisFromED(){
    	queue<int> q;
    	q.push(ed);
    	vis_getDisFromED[ed]=1;
    	while(!q.empty()){
    		int nowU=q.front();
    		q.pop();
    		for(int i=head[nowU];i;i=e[i].nxt){
    			int nowV=e[i].to;
    			if(!vis_getDisFromED[nowV]){
    				vis_getDisFromED[nowV]=1;
    				dis_fromED[nowV]=dis_fromED[nowU]+e[i].w;
    				q.push(nowV);
    			}
    		}
    	}
    }
    ll dep_noDiameter[MAXN];//不经过直径的最大深度 
    ll dfs_noDiameter(int x,int fa){
    	ll maxDep=dep_noDiameter[x];
    	for(int i=head[x];i;i=e[i].nxt){
    		int nowV=e[i].to;
    		if(nowV==fa||inDiameter[nowV])continue;
    		dep_noDiameter[nowV]=dep_noDiameter[x]+e[i].w;
    		ll tmp=dfs_noDiameter(nowV,x);
    		maxDep=max(maxDep,tmp);
    	}
    	return maxDep;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n-1;i++){
    		ll a,b,c;
    		cin>>a>>b>>c;
    		addEdge(a,b,c);
    		addEdge(b,a,c);
    	}
    	st=bfs(1);
    	ed=bfs(st);//直径
    	cout<<dep[ed]<<endl;
    	markDiameter();//标记直径上点 
    	bfs_getDisFromST();
    	bfs_getDisFromED();//获取每个点到两个端点的距离 
    	int l=st,r=ed;//必经边端点 
    	int tmp=from[ed];
    	while(tmp){//r
    		if(tmp==st)break;
    		dep_noDiameter[tmp]=0;
    		ll nowMaxDep=dfs_noDiameter(tmp,0);
    		if(nowMaxDep==dis_fromED[tmp]){
    			r=tmp;
    		}
    		tmp=from[tmp];
    	}
    	bfs(ed);//重新获取from数组
    	tmp=from[st];
    	while(tmp){//l
    		if(tmp==ed||tmp==r)break;
    		ll nowMaxDep=dfs_noDiameter(tmp,0);
    		if(nowMaxDep==dis_fromST[tmp])l=tmp;
    		tmp=from[tmp];
    	} 
    	int cnt=0;
    	tmp=l;
    	while(tmp){
    		if(tmp==r)break;
    		cnt++;
    		tmp=from[tmp];
    	}
    	printf("%d
    ",cnt);
    	return 0;
    }
    

      

  • 相关阅读:
    [转] CSocket 和CAsyncSocket类介绍
    error C2275: 'SOCKET' : illegal use of this type as an expression
    tagVARIANT、VARIANT、_variant_t和COleVariant
    使用MFC WinInet进行FTP中文件的简单上传和下载功能
    【转】VS2008快速将代码中字符串改为_T(“”)风格的方法
    【转】Internet与Intranet区别
    POSIX是什么?
    Ocx控件注册不成功?可能是tlb文件导致~
    十三种基于直方图的图像全局二值化算法原理、实现、代码及效果(转)
    图像匹配之欧式距离算法(转)
  • 原文地址:https://www.cnblogs.com/zbsy-wwx/p/11746614.html
Copyright © 2011-2022 走看看