bzoj3124: [Sdoi2013]直径 树形dp two points

题目链接

bzoj3124: [Sdoi2013]直径

题解

发现所有直径都经过的边
一定在一条直径上,并且是连续的
在一条直径上找这段区间的两个就好了

代码

#include<map> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#define gc getchar()
#define pc putchar
#define int long long 
inline int read() { 
    int x = 0,f = 1; 
    char c = gc; 
    while(c < '0' || c > '9') { if(c == '-') f =- 1;c = gc;}  
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc; 
    return x * f; 
} 
void print(int x) { 
    if(x < 0) { 
        pc('-'); 
        x = -x; 
    } 
    if(x >= 10) print(x / 10); 
    pc(x % 10 + '0'); 
} 
int n; 
const int maxn = 400007; 
struct node { 
    int v,w,next;
} edge[maxn << 1]; 
int head[maxn],num = 0; 
inline void add_edge(int u,int v,int w) { 
    edge[++ num].v = v; edge[num].w = w; edge[num].next = head[u]; head[u] = num; 
} 
int st,mx,dis[maxn],fa[maxn]; 
void dfs(int x,int Fa) { 
    if(dis[x] > mx) { 
        mx = dis[x]; st = x; 
    } 
    fa[x] = Fa; 
    for(int i = head[x];i;i = edge[i].next) {
        int v = edge[i].v; 
        if(v == Fa) continue; 
        dis[v] = dis[x] + edge[i].w; 
        dfs(v,x); 
    } 
} 
int chain[maxn]; 
int rdis[maxn],MX; 
bool vis[maxn]; 
void rdfs(int x,int Fa) { 
    vis[x] = true; 
    MX = std::max(MX,rdis[x]); 
    for(int i = head[x];i;i = edge[i].next) { 
        int v = edge[i].v; 
        if(vis[v] || v == Fa) continue; 
        rdis[v] = rdis[x] + edge[i].w; 
        rdfs(v,x); 
    } 
} 
main() { 
    //freopen("3.in","r",stdin);  
     n = read(); 
    for(int u,v,w,i = 1;i < n;++ i) { 
        u = read(),v = read(),w = read(); 
        add_edge(u,v,w); 
        add_edge(v,u,w); 
    } 
    dfs(1,0); 
    dis[st] = 0; 
    mx = 0; 
    dfs(st,0); 
    int len = 0; 
    while(st) { 
        chain[++ len] = st; 
        vis[st] = true; 
        st = fa[st]; 
    } 
    int l = len,r = 1; 
    for(int i = len;i >= 1;-- i) { 
        MX = 0; 
        rdfs(chain[i],0); 
        if(!MX) continue; 
        if(MX == dis[chain[i]]) l = i; 
        if(MX == mx - dis[chain[i]]) {r = i;break;} 
    }    
    print(mx); 
    pc('\n'); 
    print(l - r); 
}   
/* 
6 
3 1 1000
1 4 10
4 2 100
4 5 50
4 6 100
*/

posted @ 2018-11-01 15:00  zzzzx  阅读(210)  评论(0编辑  收藏  举报