[BZOJ 3124] 直径

Link:

BZOJ 3124 传送门

Solution:

对于第二问,要先推出几个性质:

1、这些边在一条直径上

2、这些边一定是连续的

这类性质主要就靠瞎蒙再用反证法证一证就好了

(证不出来感性认知一下就直接上吧

 

接下来只要在任意一个直径上寻找连续的可行边即可

设直径的两个端点分别为$S,T$,可以使用尺取法的思路,维护左右两个边界

对于每个点判断其是否有一条不经过直径但与该点到$S/T$距离相同的路径,如果有,则将左/右边界移动

(这里有一个剪枝,如果是从$T->S$判断,只要有点$x$有第二条距离为$dist(S,x)$的路径,则可以直接退出,可用反证法证明)

 

这里的思路有些类似于BZOJ 2282

但此题对于每个节点的判断不具有决策单调性,因此不能二分

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN=2e5+10;
bool on_dia[MAXN];
struct edge{int nxt,to;ll w;}e[MAXN<<2];
ll dia,dist[MAXN];
int n,head[MAXN],rt1,rt2,f[MAXN],tot=0,cur=0;

void add_edge(int from,int to,int w)
{
    e[++tot].nxt=head[from];e[tot].to=to;
    e[tot].w=w;head[from]=tot;
}

void dfs(int x,int anc) //求直径 
{
    for(int i=head[x];i;i=e[i].nxt)
    {
        if(e[i].to==anc) continue;
        f[e[i].to]=x;dist[e[i].to]=dist[x]+e[i].w;
        dfs(e[i].to,x);
    }
}

void find_max(int x,int anc) //计算非直径上的最远距离 
{
    if(dist[x]>cur) cur=dist[x];
    for(int i=head[x];i;i=e[i].nxt)
    {
        if(e[i].to==anc || on_dia[e[i].to]) continue;
        dist[e[i].to]=dist[x]+e[i].w;
        find_max(e[i].to,x);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;ll z;scanf("%d%d%lld",&x,&y,&z);
        add_edge(x,y,z);add_edge(y,x,z);
    }
    
    dfs(1,0);
    for(int i=1;i<=n;i++) if(dist[i]>dist[rt1]) rt1=i;
    dist[rt1]=0;dfs(rt1,0);
    for(int i=1;i<=n;i++) if(dist[i]>dist[rt2]) rt2=i;
    
    on_dia[rt1]=true;dia=dist[rt2];
    for(int i=rt2;i!=rt1;i=f[i])
        on_dia[i]=true;
    printf("%lld\n",dia);
    
    int l=rt1,r=rt2;
    for(int i=f[rt2];i!=rt1;i=f[i])
    {
        ll pl=dist[i],pr=dia-dist[i];
        dist[i]=cur=0;find_max(i,0);
        if(cur==pl) {l=i;break;} //如果左端有新路径则直接退出 
        if(cur==pr) r=i;
    }
    
    int res=0;
    for(int i=r;i!=l;i=f[i])
        res++;
    printf("%d",res);
    return 0;
}

 

Review:

 1、$dfs$时的代码技巧

如果递归结束后不好确定经过哪些点,最好在递归过程中更新结果

 

2、推结论

多用反证法和假设法检验某种情况是否可能出现

尽可能利用结论进行剪枝

 

posted @ 2018-06-30 14:13  NewErA  阅读(204)  评论(0编辑  收藏  举报