[Sdoi2013]直径(树的直径)

Posted 神犇(shenben)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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;
} 

 

以上是关于[Sdoi2013]直径(树的直径)的主要内容,如果未能解决你的问题,请参考以下文章

[树的直径] SDOI2013 直径

[Sdoi2013]直径(树的直径)

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

[Sdoi2013]直径

3124: [Sdoi2013]直径

P3304 [SDOI2013]直径(模板树直径的必经边)