bzoj3124: [Sdoi2013]直径
发现所有直径都经过的边 一定在一条直径上,并且是连续的 在一条直径上找这段区间的两个就好了
#include #include #include #include #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 */