[Sdoi2013]直径(树的直径)

//36分

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;

#define setfire(name) freopen(#name".in","r",stdin);freopen(#name".out","w",stdout);
#define fre(name) freopen(#name".txt","r",stdin);
#ifdef WIN32
#define LL "%lld"
#else
#define LL "%I64d"
#endif

const int N=2e5+5;
const int Z=2005;
int n,S1,S2,la,lb,s_cnt,b[N],stack[N],prev[N];char s[50];bool vis[N];
struct edge{int u,v,next;ll w;}e[N<<1];int tot=1,head[N];
int dep[N],fa[N][19];
ll ans,LEN,dis[N],dist[N];
bool mark[Z][Z];
struct data{int x,y;}state[N];
inline int read(){
    int x=0;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x;
}
inline void add(int x,int y,int z){
    e[++tot].u=x;e[tot].v=y;e[tot].w=z;e[tot].next=head[x];head[x]=tot;
    e[++tot].u=y;e[tot].v=x;e[tot].w=z;e[tot].next=head[y];head[y]=tot;
}
void BFS(int S){
    int top=1;
    stack[top]=S;dep[S]=1;fa[S][0]=S;
    while(top){
        int x=stack[top--];
        for(int i=head[x];i;i=e[i].next){
            if(e[i].v!=fa[x][0]){
                fa[e[i].v][0]=x;
                dep[e[i].v]=dep[x]+1;
                dist[e[i].v]=dist[x]+e[i].w;
                stack[++top]=e[i].v;
            }
        }
    }
}
inline int bfs(int S){
    memset(dis,-1,sizeof dis);
    memset(vis,0,sizeof vis);
    int id=0,mx=-1,top=1;
    stack[top]=S;dis[S]=0;vis[S]=1;
    while(top){
        int x=stack[top--];
        for(int i=head[x];i;i=e[i].next){
            if(!vis[e[i].v]&&dis[e[i].v]<dis[x]+e[i].w){
                vis[e[i].v]=1;
                dis[e[i].v]=dis[x]+e[i].w;
                if(dis[e[i].v]>mx) mx=dis[e[i].v],id=e[i].v;
                stack[++top]=e[i].v;
            }
        }
    }
    return id;
}
void gosolve(int S,int T){
    memset(vis,0,sizeof vis);
    int id=0,mx=-1,top=1;
    stack[top]=S;vis[S]=1;
    while(top){
        int x=stack[top--];
        for(int i=head[x];i;i=e[i].next){
            if(!vis[e[i].v]){
                vis[e[i].v]=1;
                prev[e[i].v]=i;
                if(e[i].v==T){top=0;break;}
                stack[++top]=e[i].v;
            }
        }
    }
    for(int i=T;i!=S;i=e[prev[i]^1].v)  b[prev[i]>>1]++;
}
int lca(int a,int b){
    if(dep[a]<dep[b]) swap(a,b);
    int t=dep[a]-dep[b];
    for(int i=0;i<=18;i++){
        if(t&(1<<i)){
            a=fa[a][i];
        }
    }
    if(a==b) return a;
    for(int i=18;i>=0;i--){
        if(fa[a][i]!=fa[b][i]){
            a=fa[a][i];
            b=fa[b][i];
        }
    }
    return fa[a][0];
}
void init(){
    n=read();
    for(int i=1,x,y,z;i<n;i++) x=read(),y=read(),z=read(),add(x,y,z);
}
void dp_tree_len(int x,int fa){
    for(int i=head[x],y;i;i=e[i].next){
        if((y=e[i].v)!=fa){
            if((x==la&&y==lb)||(x==lb&&y==la)) continue;
            dp_tree_len(y,x);
            LEN=max(LEN,dis[x]+dis[y]+e[i].w);
            dis[x]=max(dis[x],dis[y]+e[i].w);
        }
    }
}
void work(){
    if(n<=100){
        BFS(1);
        for(int i=1,mx=0;i<=n;i++) if(dist[i]>mx) mx=dist[i],S1=i;
        S2=bfs(S1);
        LEN=dis[S2];
        printf("%I64d\n",LEN);
        for(int j=1;j<=18;j++){
            for(int i=1;i<=n;i++){
                fa[i][j]=fa[fa[i][j-1]][j-1];
            }
        }
        ll lt;
        for(int i=1,anc;i<=n;i++){
            for(int j=1;j<i;j++){
                if(mark[i][j]) continue;
                anc=lca(i,j);
                lt=dist[i]+dist[j]-dist[anc]*2;
                if(lt==LEN) mark[i][j]=1,state[++s_cnt]=(data){i,j};
            }
        }
        //直径条数
        for(int i=1;i<=s_cnt;i++){
            gosolve(state[i].x,state[i].y);
        }
        int num=0;
        for(int i=1;i<=n;i++) if(b[i]==s_cnt) num++;
        printf("%d",num);
    }
    else{
        dp_tree_len(1,1);
        printf("%I64d\n",LEN);
    }
}
int main(){
    freopen("diameter.in","r",stdin);
    freopen("diameter.out","w",stdout);
    int size=64<<20;
    char *p=(char*)malloc(size)+size;
    __asm__("movl %0,%%esp\n"::"r"(p));
    init();
    work();
    return 0;
} 
时间: 2024-10-10 09:27:40

[Sdoi2013]直径(树的直径)的相关文章

[SDOI2013]直径 (树的直径,贪心)

题目链接 Solution 我们直接找到一条直径 \(s\),起点为 \(begin\),终点为 \(end\). 从前往后遍历点 \(u\) ,若子树中最大的距离与 \(dis(u,begin)\) 相等. 很显然这个点不在公共线段上,很显然可以用子树的中的一段接上,形成一条新的直径. 然后从后往前遍历,同样的道理... 然后找到两个节点 \(l,r\) 然后答案即为 \(r-l\). 记得要开 \(longlong\). Code #include<bits/stdc++.h> #defi

树的直径、树的重心与树的点分治

树的直径 树的直径(Diameter)是指树上的最长简单路. 直径的求法:两遍搜索 (BFS or DFS) 任选一点w为起点,对树进行搜索,找出离w最远的点u. 以u为起点,再进行搜索,找出离u最远的点v.则u到v的路径长度即为树的直径. 简单证明: 如果w在直径上,那么u一定是直径的一个端点.反证:若u不是端点,则从直径另一端点到w再到u的距离比直径更长,与假设矛盾. 如果w不在直径上,且w到其距最远点u的路径与直径一定有一交点c,那么由上一个证明可知,u是直径的一个端点. 如果w到最远点u

树的直径与树的重心

树的直径 树的直径是指树上的最长简单路. 直径的求法:两遍搜索 任选一点w为起点,对树进行搜索,找出离w最远的点u. 以u为起点,再进行搜索,找出离u最远的点v. 则u到v的路径长度即为树的直径. ---------------------------------------------------------------- 树的重心树的重心: 找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心. 删去重心后,生成的多棵树尽可能平衡. 树的重心可以通过简单的两次搜索求出,

hdu 4612 缩点 桥 树的直径

// http://acm.hdu.edu.cn/showproblem.php?pid=4612 // 大致题意: 给n个点和m条边,组成一个无向连通图,问  给我加一条边的权力(可连接任意两点)->让图的桥数量最小,输出此时桥的数量.(2<=N<=200000, 1<=M<=1000000) // 无向环里面的边没有桥,缩点,因为是连通图,所以缩完点后构成了一棵树,每条树边都是一个桥.要加一条边使得加完后图的桥数最小,结合上述,所以选择连接树直径的两端点.ans = 原先

[树的直径] SDOI2013 直径

SDOI2013 直径 题目描述 小Q最近学习了一些图论知识.根据课本,有如下定义.树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度.如果一棵树有N个节点,可以证明其有且仅有N-1 条边. 路径:一棵树上,任意两个节点之间最多有一条简单路径.我们用 dis(a,b)表示点a和点b的路径上各边长度之和.称dis(a,b)为a.b两个节点间的距离. 直径:一棵树上,最长的路径为树的直径.树的直径可能不是唯一的. 现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有

SDOI2013 直径(树的直径必经边)

SDOI2013 直径 题目传送 sol: 先求出任一直径同时把直径拎出来,树的非直径部分全部挂在直径上(如下). 对于直径上的每一个点i,如果存在它到非直径上点的最大距离\(g[i]\)等于它到直径两端点中较短的那一段\(d[i]\), 则说明这一段也可以成为直径中的一部分. 而我们需要得到所有直径的交,画图可以发现假设两端(以中点为界)都存在上述的点,最逼近的两点间的边即为所求! 具体可以看代码实现. code: #include<bits/stdc++.h> #define IL inl

poj 1985 Cow Marathon 【树的直径】

题目:poj 1985 Cow Marathon 题意:给出一个树,让你求树的直径. 分析: 树的直径:树上两点之间的最大距离. 我们从任意一点出发,BFS一个最远距离,然后从这个点出发,在BFS一个最远距离,就是树的直径. AC代码: /* POJ:1985 Cow Marathon 2014/10/12/21:18 Yougth*/ #include <cstdio> #include <iostream> #include <algorithm> #include

poj1849(求树的直径)

题目链接:http://poj.org/problem?id=1849 题意:有一颗n个结点的带权的无向树, 在s结点放两个机器人, 这两个机器人会把树的每条边都走一遍, 但是最后机器人不要求回到出发点. 问你两个机器人走的路总长之和的最小值是多少? 分析:如果从某点出发遍历完一棵树再回来,那么所有边都会走两遍,而从某点有两个机器人出发去遍历,因为不用回来,所以最后那两个人距离越远越好,可以从树的直径上某个点背道而驰,那么这段距离(树的直径)只走了一遍,其他的要走两遍,所以ans=sum*2-l

SDUT OJ 3045 迷之图论 (树的直径)

题目地址:SDUT OJ 3045 这题比赛的时候想的差不多..但是总是觉得不对..写了一次就没再写,然后删了..当时没想到的是第二次求出来的就是最长链..当时想到的两次bfs找最大值(这一种方法其实结果也对..TAT..),还有找到点后在回溯减去重点等等..但总觉得好像都不太对...赛后才知道这题原来是树的直径.....牡丹江区域现场赛的时候遇到过,不过赛后也没看... 找树的直径的方法其实就是先任取一点进行bfs,找到最远的一点,这时最远的一点肯定是最长链端点之一,然后再从这一最远点开始bf

hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v(level最深)该点必然是树的直径的一个端点,,再从该点出发,bfs,到最深的一点,该点深度就是直径.(证明:先假设u,是直径上一点,S,T是直径的端点,设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v:若u不是直径上一点,设u到直径上的一点为x,同理易证. 最后 缩