BZOJ3124 SDOI2013 直径 DFS

题意:给定一棵树,求这棵树直径的长度和所有直径有多少个公共点。

题解:求直径感觉DFS比BFS好写太多,但是大数据本地爆栈OJ却不爆……思路和BFS版的差不多,第一问是个裸题。因为书中任意两点间有且仅有一条路径,所以所有直径的公共点一定是连续的一段。我们从左向右枚举直径上所有点,如果一个点到直径外一点的距离等于到直径左端的距离,那么这个点就是连续的公共点的最左边的一个,同理可找到最右边的一个。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

const int MAXN=200000+2;
struct Hash{
    int u;
    ll w;
    Hash *Next;
    Hash(){}
    Hash(int _u,ll _w,Hash *_Next):u(_u),w(_w),Next(_Next){}
}*Tab[MAXN],Mem[2*MAXN];
int N,A,B,T,f[MAXN],cnt;
bool Flag[MAXN];
ll Ans=-1,D,g[MAXN];

void Insert(int u,int v,ll w){ Tab[u]=&(Mem[cnt++]=Hash(v,w,Tab[u]));}

void DFS1(int x,int l,ll d){
    if(d>D) D=d,T=x;
    for(Hash *p=Tab[x];p;p=p->Next)
        if(p->u!=l) f[p->u]=x,g[p->u]=p->w,DFS1(p->u,x,d+p->w);
}

void DFS2(int x,int l,ll d){
    if(d>D) D=d;
    for(Hash *p=Tab[x];p;p=p->Next)
        if(p->u!=l && !Flag[p->u]) DFS2(p->u,x,d+p->w);
}

int main(){
    cin >> N;
    int u,v;ll w;
    for(int i=1;i<N;i++){
        scanf("%d %d %lld",&u,&v,&w);
        Insert(u,v,w),Insert(v,u,w);
    }

    D=0,DFS1(1,-1,0),A=T;
    D=0,DFS1(A,-1,0),B=T;
    Ans=D,cout << Ans << endl;

    Flag[A]=1;
    for(int i=B;i!=A;i=f[i]) Flag[i]=1;
    int l=0,r=0;ll d=0;
    for(int i=B,t;i;i=f[i]){
        t=g[i],r++,D=0,DFS2(i,-1,0);
        if(D==d) l=r;
        if(D==Ans-d) break;
        d+=t;
    }
    cout << r-l << endl;

    return 0;
}
View Code

 

posted @ 2017-03-11 18:41  WDZRMPCBIT  阅读(106)  评论(0编辑  收藏  举报