挺进

zz:https://blog.csdn.net/rzo_kqp_orz/article/details/52280525
小Z又开始了ETG。ETG的地图是树形的,相邻两个房间有一定距离,一开始,系统会随机断掉一条边,这样,这张
地图就被分成了两个连通块。显然,狡猾的系统会把四个宝箱两两分布在每个联通的最远点对上。一开始,小Z会
出生在一个有宝箱的房间(系统还是有点良心的),然后小Z“咚咚咚咚”一路过关斩将走到有另外一个宝箱的所
在地(显然小Z走最短路),到达第二个宝箱所在地后,系统会又很良心地把他送到另一个连通块的某个宝箱处,
然后小Z又“咚咚咚咚咚”,拿到了最后一个宝箱。然后,他就通关了。显然对小Z来说通关是肯定的,所以小Z想
知道他最多会走多少距离。

Input
输入第一行包含一个整数N,表示房间个数。
接下来N-1行,每行3个正整数x,y,d表示,房间x与房间y的距离为d。
N<=100,000 ,di<=100,000 。

Output
输出一行,包含一个整数,表示小Z最远走的距离。

Sample Input
6
1 3 4
2 3 1
2 5 3
2 6 2
3 4 5

Sample Output
14

Data Constraint

对于50%的数据满足N<=1000 。
对于100%的数据满足

一句话题意
给出一棵树,你可以选择断掉某一条边,然后取生成的两棵树的直径和。求这个和的最大值。
【50%】n<=1000
枚举断哪一条边,然后暴力求直径。
【100%解法1】n<=10^5
用线段树维护树的直径。
枚举断哪一条边,这相当于分离出原树的一棵子树,我们可以在线段树中查找到这棵子树的直径,然后剩下的区间合并一下得到另一个直径。
如果用倍增求lca时间是O(n log^2),会被卡。
如果用rmq求lca时间是O(n log)
//线段树维护树的直径:http://blog.csdn.net/rzo_kqp_orz/article/details/52280811
【100%解法2】
题解说这是裸的树形dp!?
题解原话:“裸的树形 DP,记录 d1[i] (最长链),d2[i] (次长链),fa[i] ( i 的父亲及以上的最长路)即可。时间复杂度O(n)。”
思路是非常简单的,但是维护过程打起来讨论较多。

#include<cmath>
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long LL;

const int maxn=(1e5)+5, MX=18;

struct TR{
    int x,y;
    LL len;

    TR(int X=0,int Y=0,LL LEN=0) {x=X, y=Y, len=LEN;}
};

int n;

int tot,go[2*maxn],next[2*maxn],f1[maxn];
LL val[2*maxn];
void ins(int x,int y,LL z)
{
    go[++tot]=y;
    val[tot]=z;
    next[tot]=f1[x];
    f1[x]=tot;
}

int fa[2*maxn][MX+5],deep[maxn],ap[2*maxn],fir[2*maxn],Log[2*maxn],er[MX+5];
void rmq_pre()
{
    fo(i,1,ap[0]) fa[i][0]=ap[i], Log[i]=log(i)/log(2);
    fo(i,0,MX) er[i]=1<<i;
    fo(j,1,MX)
        fo(i,1,ap[0])
        {
            fa[i][j]=fa[i][j-1];
            if (i+er[j-1]<=ap[0] && deep[fa[i+er[j-1]][j-1]]<deep[fa[i][j]])
                fa[i][j]=fa[i+er[j-1]][j-1];
        }
}
int lca(int x,int y)
{
    x=fir[x], y=fir[y];
    if (x>y) swap(x,y);
    int t=Log[y-x+1];
    return (deep[fa[x][t]]<deep[fa[y-er[t]+1][t]]) ?fa[x][t] :fa[y-er[t]+1][t] ;
}

int st[maxn],en[maxn],sum,Tbh[maxn];
LL dis[maxn];
void dfs_pre(int k,int last,LL s)
{
    deep[k]=deep[last]+1;
    dis[k]=s;
    ap[++ap[0]]=k, fir[k]=ap[0];
    Tbh[++sum]=k, st[k]=sum;
    for(int p=f1[k]; p; p=next[p]) if (go[p]!=last)
    {
        dfs_pre(go[p],k,s+val[p]);
        ap[++ap[0]]=k;
    }
    en[k]=sum;
}

TR tr[4*maxn];
LL DIS(int x,int y) {return dis[x]+dis[y]-dis[lca(x,y)]*2;}
TR merge(TR a,TR b)
{
    TR re= (a.len>b.len) ?a :b;
    if (DIS(a.x,b.x)>re.len) re=TR(a.x,b.x,DIS(a.x,b.x));
    if (DIS(a.x,b.y)>re.len) re=TR(a.x,b.y,DIS(a.x,b.y));
    if (DIS(a.y,b.x)>re.len) re=TR(a.y,b.x,DIS(a.y,b.x));
    if (DIS(a.y,b.y)>re.len) re=TR(a.y,b.y,DIS(a.y,b.y));
    return re;
}
void tr_js(int k,int l,int r)
{
    if (l==r)
    {
        tr[k].x=tr[k].y=Tbh[l];
        tr[k].len=0;
        return;
    }
    int t=k<<1, t1=(l+r)>>1;
    tr_js(t,l,t1), tr_js(t+1,t1+1,r);
    tr[k]=merge(tr[t],tr[t+1]);
}
TR tr_cx(int k,int l,int r,int x,int y)
{
    if (l==x && r==y) return tr[k];
    int t=k<<1, t1=(l+r)>>1;
    if (y<=t1) return tr_cx(t,l,t1,x,y);
        else if (x>t1) return tr_cx(t+1,t1+1,r,x,y);
            else return merge(tr_cx(t,l,t1,x,t1),tr_cx(t+1,t1+1,r,t1+1,y));
}

LL ans;
void dfs(int k,int last)
{
    for(int p=f1[k]; p; p=next[p]) if (go[p]!=last)
    {
        int St=st[go[p]], En=en[go[p]];
        if (St==1)
        {
            ans=max(ans,tr_cx(1,1,n,St,En).len+tr_cx(1,1,n,En+1,n).len);
        } else if (En==n)
        {
            ans=max(ans,tr_cx(1,1,n,1,St-1).len+tr_cx(1,1,n,St,En).len);
        } else
        {
            TR t=merge(tr_cx(1,1,n,1,St-1),tr_cx(1,1,n,En+1,n));
            ans=max(ans,t.len+tr_cx(1,1,n,St,En).len);
        }

        dfs(go[p],k);
    }
}

int main()
{
    scanf("%d",&n);
    fo(i,1,n-1)
    {
        int x,y; LL d;
        scanf("%d %d %lld",&x,&y,&d);
        ins(x,y,d), ins(y,x,d);
    }

    dfs_pre(1,0,0);
    rmq_pre();
    tr_js(1,1,n);

    dfs(1,0);

    printf("%lld\n",ans);
}

#include <cstdio>
#include <cstring>
#include <algorithm>
#define i64 long long
using namespace std;

const int N = 1e5 + 10;
int n, r[N], tot;
i64 ans;

struct edge{int t, l, n;} e[N * 2];

struct link {
    i64 v1, v2, v3;
    int u1, u2, u3;
    void ins(int u, i64 v) {
        if (v > v1) u3 = u2, v3 = v2, u2 = u1, v2 = v1, u1 = u, v1 = v;
        else if (v > v2) u3 = u2, v3 = v2, u2 = u, v2 = v;
        else if (v > v3) u3 = u, v3 = v;
    }
} l[N];

i64 max(i64 x, i64 y) {return x > y ? x : y;}

void add(int x, int y, int z) {
    e[++ tot].t = y; e[tot].l = z; e[tot].n = r[x]; r[x] = tot;
}

void dfs(int u, int fa) {
    l[u].u1 = l[u].u2 = l[u].v1 = l[u].v2 = 0;
    for (int i = r[u]; i; i = e[i].n) {
        int v = e[i].t;
        if (v == fa) continue;
        dfs(v, u);
        i64 t = l[v].v1 + e[i].l;
        l[u].ins(v, t);
    }
}

void awn(int u, int fa, i64 ll, i64 mx) {
    for (int i = r[u]; i; i = e[i].n) {
        int v = e[i].t;
        if (v == fa) continue;
        i64 t = 0, mm = 0;
        if (l[u].u1 == v) t = l[u].v2;
        else t = l[u].v1;
        if (l[u].u1 == v) mm = l[u].v2 + l[u].v3;
        else if (l[u].u2 == v) mm = l[u].v1 + l[u].v3;
        else mm = l[u].v1 + l[u].v2;
        ans = max(ans, l[v].v1 + l[v].v2 + max(mm, max(mx, ll + t)));
        awn(v, u, max(ll, t) + e[i].l, max(mm, max(mx, ll + t)));
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; i ++) {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w); add(v, u, w);
    }
    dfs(1, 0);
    awn(1, 0, 0, 0);
    printf("%lld", ans);
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/cutemush/p/11831036.html
今日推荐