Noip2015 运输计划 【二分答案】【差分】【LCA】

本文介绍了一种基于图论的算法优化方法,通过构建复杂的图结构来解决特定问题。使用深度优先搜索和动态规划等技术,实现了对路径查找、距离计算等问题的有效处理。

=。=

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define max(a, b) (a) > (b) ? (a) : (b)
inline void read(int &x) {
    x = 0;
    char c = getchar();
    while(c<'0'||c>'9') c = getchar();
    while(c>='0'&&c<='9') x = x * 10 + c - '0', c = getchar();
    return;
}
const int maxn = 300010;
int n, m, tot,last[maxn],dis[maxn],top[maxn],father[maxn],son[maxn];
int edge_back_father[maxn],deep[maxn],upline,tag[maxn],dmax,wmax,downline;
struct ASK{
    int u,v,dis,lca;
}ask[maxn];
struct Edge{
    int u,v,w,to;
    Edge(){}
    Edge(int u, int v, int w, int to) : u(u), v(v), w(w), to(to) {};
}e[maxn*2+6];
void addedge(int u, int v, int w) {
    e[++tot] = Edge(u,v,w,last[u]);
    last[u] = tot;
}
void dfs1(int x) {
    son[x] = 1;
    deep[x] = deep[father[x]] + 1;
    for(int i=last[x]; i; i=e[i].to) {
        if(e[i].v != father[x]) {
            father[e[i].v] = x;
            int v = e[i].v;
            edge_back_father[v] = i;
            dis[v] = dis[x] + e[i].w;
            dfs1(v);
            son[x] += son[v];
        }   
    }
}
void dfs2(int x) {
    int t=0;
    if(!top[x]) top[x] = x;
    for(int i=last[x]; i; i=e[i].to) 
        if(e[i].v!=father[x] && son[e[i].v] > son[t]) t = e[i].v;
    if(t) top[t] = top[x];
    for(int i=last[x]; i; i=e[i].to)
        if(e[i].v!=father[x]) dfs2(e[i].v);
}
inline int lca(int x, int y) {
    while(top[x] != top[y]) {
        if(deep[top[x]] < deep[top[y]]) std::swap(x, y);
        x = father[top[x]];
    }
    return (deep[x] > deep[y]) ? y : x;
}
void dfs_date(int x) {
    for(int i=last[x]; i; i=e[i].to) {
        if(e[i].v != father[x]) {
            dfs_date(e[i].v);
            tag[x] += tag[e[i].v];
        }
    }
}
bool check(int x) {
    int dec=0 , cnt=0;
    memset(tag, 0, sizeof(tag));
    for(int i=1; i<=m; i++) {
        if(ask[i].dis > x) {
            dec = max(dec, ask[i].dis - x);
            tag[ask[i].u]++;
            tag[ask[i].v]++;
            tag[ask[i].lca] -= 2;
            cnt++;
        }
    }
    dfs_date(1);
    for(int i=1; i<=n; i++) 
        if(cnt == tag[i] && e[edge_back_father[i]].w >= dec)
            return true;
        return false;   
}
inline int div() {
    int l = downline, r = upline, ans = 0;
    while(l <= r) {
        int mid = l + r >> 1;
        if(check(mid)) r = mid - 1, ans = mid;
        else l = mid + 1;
    }
    return ans;
}
int main(){
    read(n);read(m);
    for(int i=1,u,v,w; i<n; i++) {
        read(u); read(v); read(w);
        addedge(u,v,w);
        addedge(v,u,w);
        wmax = max(wmax,w);
    }
    dfs1(1);
    dfs2(1);
    for(int i=1; i<=m; i++) {
        read(ask[i].u);
        read(ask[i].v);
        ask[i].lca = lca(ask[i].u, ask[i].v);
        ask[i].dis = dis[ask[i].u] + dis[ask[i].v] - 2*dis[ask[i].lca];
        upline = max(upline, ask[i].dis);
        dmax = max(dmax, ask[i].dis);
    }
    downline = dmax - wmax;
    printf("%d",div());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值