zoukankan      html  css  js  c++  java
  • BZOJ1509: [NOI2003]逃学的小孩 (树形DP)

    题意:给一棵树 选三个点A,B,C 求A到B的再从B到C的距离最大值 需要满足AB的距离小于AC的距离

    题解:首先树上的最大距离就想到了直径 但是被样例误导了TAT

       BC两点构成了直径 我一开始以为A在直径上答案最大 然后再加上最接近路径长度一半的路径

       其实 A不在直径上的话显然更优啊...

       那么做法就是先求出直径 然后记录路径 枚举路上的每一个点能到达的最远的路径

       当然这个最远路径不能和直径有公共边

       复杂度的话想想还挺有意思的 从直径上走刚好遍历整棵树

    总结:突然发现这个题数据水了..

       我这个写法 在枚举直径路上的点的时候每一次都暴力memset

       假设这棵树是一条链肯定会超时的...

       如果这样的话写法就应该枚举每个点的时候把dfs到的点放进数组里

       然后再把这些点手动清空 反正过了 懒得改了..

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    using namespace std;
    typedef long long ll;
    
    int n, m, l, r, cnt, num, rt;
    ll ans1, ans2, zd;
    
    struct node
    {
        int to, nex, val;
    }E[400005];
    int head[200005];
    int pre[200005];
    int vis[200005];
    int lian[200005];
    ll dis[200005];
    ll diss[200005];
    
    void dfs(int x, int fa)
    {
        pre[x] = fa;
        int c = head[x];
        for(int i = c; i; i = E[i].nex)
        {
            int v = E[i].to;
            if(v == fa) continue;
            dis[v] = dis[x] + E[i].val;
            dfs(v, x);
        }
        if(dis[x] > dis[rt]) rt = x;
    }
    
    void dfs1()
    {
        int x = r;
        while(x != pre[l])
        {
            num++; lian[num] = x;
            vis[x] = 1;
            x = pre[x];
        }
    }
    
    void dfs2(int x, int fa)
    {
        int c = head[x];
        for(int i = c; i; i = E[i].nex)
        {
            int v = E[i].to;
            if(v == fa) continue;
            if(vis[v]) continue;
    
            diss[v] = diss[x] + E[i].val;
            dfs2(v, x);
        }
        zd = max(zd, diss[x]);
    }
    
    int main()
    {
        ans1 = 0; ans2 = 0;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i++)
        {
            int u, v, o; scanf("%d%d%d", &u, &v, &o);
            E[++cnt].to = v; E[cnt].nex = head[u]; head[u] = cnt; E[cnt].val = o;
            E[++cnt].to = u; E[cnt].nex = head[v]; head[v] = cnt; E[cnt].val = o;
        }
        dfs(1, -1); l = rt;
        memset(dis, 0, sizeof(dis));
        dfs(rt, -1); r = rt;
        ans1 = dis[r];
    
        dfs1();
        for(int i = 1; i <= num; i++)
        {
            memset(diss, 0, sizeof(diss)); zd = 0;
            dfs2(lian[i], -1);
            ll tmp = zd + min(dis[lian[i]], ans1 - dis[lian[i]]);
            ans2 = max(ans2, tmp);
        }
        printf("%lld
    ", ans1 + ans2);
        return 0;
    }
    View Code
  • 相关阅读:
    JavaScript概述
    JavaScript概述
    python语法基础
    python 网络编程
    python 日志模块
    python 异常处理
    python tricks
    记录_省赛(一)
    异或加密算法
    三目条件运算符
  • 原文地址:https://www.cnblogs.com/lwqq3/p/9175639.html
Copyright © 2011-2022 走看看