【Luogu】P3761城市(dfs)

  题目链接

  emmm我思维好水……

  想了一会lct发现好像不对,然后开始转DP稍微有一点思路,然后看了题解……

  首先可以枚举边,然后原树被你拆成了两个子树。

  设D1D2是两个子树的直径,W1W2是子树内某个点到其他点最长距离的最小值,val是断掉的边的权值

  然后呢我们发现此时的答案成为了max(max(D1,D2),W1+W2+val)

  然后可以发现W1W2可以通过枚举子树直径上的点求得。

  然后这样就TLE了23333

  一个大优化是我们可以发现枚举断掉哪条边这个步骤可以变成枚举断掉直径上哪条边,只有这样才能对答案产生影响

  然后就快了九倍……

  

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#define maxn 6000
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int n;

struct Edge{
    int next,to,val;
}edge[maxn*2];
int head[maxn],num;
inline void add(int from,int to,int val){
    edge[++num]=(Edge){head[from],to,val};
    head[from]=num;
}

int dis[maxn];
bool vis[maxn];

void find(int x,int fa,int lim){
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa||to==lim)    continue;
        dis[to]=dis[x]+edge[i].val;
        find(to,x,lim);
    }
    return;
}

void record(int x,int fa,int goal){
    if(x==goal){
        vis[x]=1;
        return;
    }
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa)    continue;
        record(to,x,goal);
        if(vis[to])    vis[x]=1;
    }
    return;
}

struct ANSWER{
    int x,y;
};

ANSWER ask(int x,int fa){
    memset(vis,0,sizeof(vis));
    memset(dis,-1,sizeof(dis));
    dis[x]=0;
    find(x,fa,fa);
    int now=0;
    for(int i=1;i<=n;++i)
        if(dis[i]>dis[now])    now=i;
    dis[now]=0;
    find(now,now,fa);
    int to=0;
    for(int i=1;i<=n;++i)
        if(dis[i]>dis[to])    to=i;
    record(now,now,to);
    ANSWER ans=(ANSWER){dis[to],0x7fffffff};
    for(int i=1;i<=n;++i)
        if(vis[i])    ans.y=min(ans.y,max(dis[to]-dis[i],dis[i]));
    return ans;
}

bool vie[maxn*3];

int main(){
    n=read();
    for(int i=1;i<n;++i){
        int from=read(),to=read(),val=read();
        add(from,to,val);
        add(to,from,val);
    }
    ask(1,0);
    for(int i=1;i<=num;i+=2){
        if(vis[edge[i].to]==0||vis[edge[i+1].to]==0)    continue;
        vie[i]=1;
    }
    int ans=0x7fffffff;
    for(int i=1;i<=num;i+=2){
        if(vie[i]==0)    continue;
        int from=edge[i].to,to=edge[i+1].to,val=edge[i].val;
        ANSWER l1=ask(from,to);    ANSWER l2=ask(to,from);
    //    printf("%d %d %d %d %d %d %d\n",from,to,val,l1.x,l1.y,l2.x,l2.y);
        ans=min(ans,max(max(l1.x,l2.x),l1.y+l2.y+val));
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-04-13 09:28  Konoset  阅读(158)  评论(0编辑  收藏  举报