BZOJ3124: [Sdoi2013]直径

来源:互联网 发布:c 语言标准函数库速查 编辑:程序博客网 时间:2024/05/16 10:47

题意清晰明了简单易懂…
误打误撞分析出来了一个性质:组成答案的边的集合一定是连续的一条链且没有分叉,根据这个性质我们可以设计一个算法。
先找出来随意一条树的直径,对于树的直径上的每个点求一条不经过这条直径的最长链。
这里写图片描述
大概是这个样子的,然后我们取最中间的一段输出即可。
(ps:数据特别特别特别水…怎么写都能过的样子?(雾))

#include<queue>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long long//by:MirrorGrayusing namespace std;const int N=411111;ll d[N];int vis[N],top,sta[N];int tot=-1,head[N],ver[N],nxt[N],len[N],fr[N];queue <int> q;void add(int x,int y,int z){    nxt[++tot]=head[x];    head[x]=tot;    ver[tot]=y;    len[tot]=z;}int bfs(int x){    memset(d,-1,sizeof(d));    int ret=0;d[x]=0;q.push(x);    while(!q.empty()){        int x=q.front();q.pop();        if(d[ret]<d[x])ret=x;        for(int i=head[x];~i;i=nxt[i])if(d[ver[i]]==-1){            d[ver[i]]=d[x]+len[i];            fr[ver[i]]=i;            q.push(ver[i]);        }    }    return ret;}ll dfs(int x,int f){    ll ret=0;    for(int i=head[x];~i;i=nxt[i])if(ver[i]!=f&&!vis[i>>1])    ret=max(ret,dfs(ver[i],x)+len[i]);    return ret;}int main(){    memset(head,-1,sizeof(head));    int n;scanf("%d",&n);    for(int i=1;i<n;i++){        int a,b,c;scanf("%d%d%d",&a,&b,&c);        add(a,b,c);add(b,a,c);    }    int p1,p2;p2=bfs(p1=bfs(1));    ll dis=d[p2];int tmp=p2;    printf("%lld\n",dis);    while(true){        sta[++top]=tmp,vis[fr[tmp]>>1]=true;        if(tmp==p1)break;        tmp=ver[fr[tmp]^1];    }    p1=top,p2=0;    for(int i=1;i<=top;i++){        ll tmp=dfs(sta[i],-1);        if(tmp&&tmp+max(dis-d[sta[i]],d[sta[i]])==dis){            if(d[sta[i]]+tmp==dis)p1=min(p1,i);            else p2=max(p2,i);        }    }    if(p1==top)p1=0;if(p2==0)p2=top;    printf("%d\n",p2-p1);    return 0;}/*111 2 12 3 13 4 100004 5 100005 6 15 10 26 7 16 9 12 8 13 11 2*/
0 0