upc 6346DIsruption【树链剖分】

6346: Disruption

时间限制: 1 Sec  内存限制: 128 MB
提交: 28  解决: 6
[提交] [状态] [讨论版] [命题人:admin]

题目描述

Farmer John prides himself on running a well-connected farm. The farm is a collection of N pastures (2≤N≤50,000), pairs of which are connected with N−1 bi-directional pathways, each having unit length. Farmer John notices that using an appropriate series of these pathways, it is possible to travel from any pasture to any other pasture.
Although FJ's farm is connected, he worries what might happen if one of the pathways gets blocked, as this would effectively partition his farm into two disjoint sets of pastures, where the cows could travel within each set but not between the sets. FJ therefore builds a set of M additional bi-directional pathways (1≤M≤50,000), each with a positive integer length at most 109. The cows still only use the original pathways for transit, unless one of these becomes blocked.

If one of the original pathways becomes blocked, the farm becomes partitioned into two disjoint pieces, and FJ will select from among his extra pathways a single replacement pathway that re-establishes connectivity between these two pieces, so the cows can once again travel from any pasture to any other pasture.

For each of the original pathways on the farm, help FJ select the shortest suitable replacement pathway.

 

输入

The first line of input contains N and M. Each of the next N−1 lines describes an original pathway using integers pp, qq, where p≠q are the pastures connected by the pathway (in the range 1…N). The remaining M lines each describe an extra pathway in terms of three integers: p, q, and r, where r is the length of the pathway. At most one pathway runs between any pair of pastures.

 

输出

For each of the N−1 original pathways in the order they appear in the input, output the length of the shortest suitable replacement pathway which would re-connect the farm if that original pathway were to be blocked. If no suitable replacement exists, output -1.

 

样例输入

6 3
1 2
1 3
4 1
4 5
6 5
2 3 7
3 6 8
6 4 5

 

样例输出

7
7
8
5
5

题意:给出一棵n个节点的树和m个带权边的一个边集,询问删除第i条树边后从边集选边使两颗子树联通的最小代价

思路:对于边集中的一条边(u,v),把这条边加到树上后,如果删除的边是u到v路径上的边,那不管怎么删除,树还是联通的,也就是说u到v路径上的边删除后加边联通的代价为cost(u,v),如果树边存在于多条路径中,那么最小代价为所有经过这条树边的(u,v)的最小权值,即对每条带权边的所覆盖的路径进行区间最小值覆盖。

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define M(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef long long LL;
const int maxn = 50005+5;
const LL mod = 1000000007;
const int inf = 1<<30;
struct Edge {
    int to,nxt;
    int u;
}e[maxn<<2];
int head[maxn];
int cnt,tot;
void addedge(int u,int v) {
    e[tot].u=u;
    e[tot].to=v;
    e[tot].nxt=head[u];
    head[u]=tot++;
 
    e[tot].u=v;
    e[tot].to=u;
    e[tot].nxt=head[v];
    head[v]=tot++;
    return ;
}
int dep[maxn],son[maxn],siz[maxn];
int top[maxn],id[maxn],rk[maxn];
int fa[maxn];
void init() {
    M(head,-1);
    M(son,-1);
    cnt=0;
    tot=0;
    return ;
}
void dfs(int u,int pre) {
    fa[u]=pre;
    siz[u]=1;
    for (int i=head[u];~i;i=e[i].nxt) {
        Edge &tmp=e[i];
        int v=tmp.to;
        if (v==pre) {
            continue;
        }
        dep[v]=dep[u]+1;
        dfs(v,u);
        siz[u]+=siz[v];
        if (son[u]==-1||siz[v]>siz[son[u]]) {
            son[u]=v;
        }
    }
    return ;
}
void dfs2(int u,int tp) {
    top[u]=tp;
    id[u]=++cnt;
    rk[cnt]=u;
    if (son[u]==-1) {
        return ;
    }
    dfs2(son[u],tp);
    for (int i=head[u];~i;i=e[i].nxt) {
        int &v=e[i].to;
        if (v==fa[u]||v==son[u]) {
            continue;
        }
        dfs2(v,v);
    }
    return ;
}
struct Node {
    int l,r,mi;
}t[maxn<<2];
int d[maxn<<2];
int Min(const int &a,const int &b) {
    return a<b?a:b;
}
void build(int l,int r,int rt) {
    t[rt].l=l;
    t[rt].r=r;
    t[rt].mi=inf;
    d[rt]=inf;
    if (l==r) {
        return ;
    }
    int mid = l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    return ;
}
void pd(int &rt) {
    if (d[rt] == inf) {
        return ;
    }
    t[rt<<1].mi=Min(t[rt<<1].mi,d[rt]);
    t[rt<<1|1].mi=Min(t[rt<<1|1].mi,d[rt]);
    d[rt<<1]=Min(d[rt<<1],d[rt]);
    d[rt<<1|1]=Min(d[rt<<1|1],d[rt]);
    d[rt]=inf;
    return ;
}
void update(int l,int r,int rt,int val) {
    if (l<=t[rt].l&&t[rt].r<=r) {
        d[rt]=Min(d[rt],val);
        t[rt].mi=Min(t[rt].mi,d[rt]);
        return ;
    }
    pd(rt);
    int mid = t[rt].l+t[rt].r>>1;
    if (l<=mid) {
        update(l,r,rt<<1,val);
    }
    if (r>mid) {
        update(l,r,rt<<1|1,val);
    }
    t[rt].mi=Min(t[rt<<1].mi,t[rt<<1|1].mi);
    return ;
}
int query(int l,int r,int rt) {
    if (l<=t[rt].l&&t[rt].r<=r) {
        return t[rt].mi;
    }
    pd(rt);
    int mid = t[rt].l+t[rt].r>>1;
    int res = inf;
    if (l<=mid) {
        res = Min(res,query(l,r,rt<<1));
    }
    if (r>mid) {
        res = Min(res,query(l,r,rt<<1|1));
    }
    return res;
}
void upd(int u,int v,int val)
{
    while(top[u]!=top[v]) {
        if(dep[top[u]]<dep[top[v]])
            swap(u,v);
        update(id[top[u]],id[u],1,val);
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]) {
        swap(u,v);
    }
    if (u==v) {
        return ;
    }
    update(id[son[u]],id[v],1,val);
    return ;
}
int main() {
 
    init();
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<n;++i) {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
    }
    dep[1]=1;
    dfs(1,-1);
    dfs2(1,1);
    build(1,cnt,1);
    while(m--) {
        int u,v,val;
        scanf("%d%d%d",&u,&v,&val);
        if (dep[u]>dep[v]) {
            swap(u,v);
        }
        upd(u,v,val);
    }
    for (int i=1;i<n;++i) {
        int pos=(i-1)<<1;
        int &u=e[pos].u;
        int &v=e[pos].to;
        if (u==fa[v]) {
            int ans=query(id[v],id[v],1);
            printf("%d\n",ans==inf?-1:ans);
        }
        else {
            int ans=query(id[u],id[u],1);
            printf("%d\n",ans==inf?-1:ans);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值