NOIP2015 D2T3运输计划

本文深入探讨了一种复杂的图算法实现,通过预处理建立快速查询结构,优化路径查找过程,并使用LCA算法加速最近公共祖先查询。针对特定问题,设计了高效的求解策略,通过巧妙的数据结构管理和动态规划技巧,实现了在大规模图上的快速查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常数是检验人傻的唯一标准……
但是今天我要推翻这句话。
我这么机智,怎么还有巨大常数……

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define Max(x,y) x>y?x:y;
#define maxn 300005
using namespace std;
void read(int &a)
{
    a=0;char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
    {
        a*=10;a+=c-'0';
        c=getchar();
    }
}
struct bi{
    int to,nxt,d;
}b[600005];
int fst[maxn],tot;
void build(int f,int t,int d)
{
    b[++tot]=(bi){t,fst[f],d};fst[f]=tot;
    b[++tot]=(bi){f,fst[t],d};fst[t]=tot;
}
int dis[maxn],deep[maxn];
int fa[21][maxn];
int dfs_n[maxn],dfs_c;
int D[maxn];
void dfs(int x)
{
    dfs_n[++dfs_c]=x;
    int v,i;
    for(i=1;i<=19;i++)
        fa[i][x]=fa[i-1][fa[i-1][x]];
    for(i=fst[x];i;i=b[i].nxt)
    {
        v=b[i].to;
        if(!fa[0][v])
        {
            fa[0][v]=x;
            deep[v]=deep[x]+1;
            dis[v]=dis[x]+b[i].d;
            D[v]=b[i].d;
            dfs(v);
        }
    }
}
int LCA;
void lca(int u,int v)
{
    if(deep[u]>deep[v]) swap(u,v);
    int t=deep[v]-deep[u];
    int i;
    for(i=0;i<=19;i++)
        if(t>>i&1)v=fa[i][v];
    for(i=19;i>=0;i--)
        if(fa[i][v]!=fa[i][u])
        {
            u=fa[i][u];
            v=fa[i][v];
        }
    if(u==v) LCA=u;
    else LCA=fa[0][u];
}
struct dd{int u,v,d,ca;}d[maxn];
bool cmp(dd a,dd b){return a.d>b.d;}
int add[maxn];
int S[maxn],top;
int main()
{
    int n,m;
    read(n);read(m);
    int u,v,w;
    for(int i=1;i<n;i++)
    {
        read(u);read(v);read(w);
        build(u,v,w);
    }
    fa[0][1]=1;dfs(1);
    for(int i=1;i<=m;i++)
    {
        read(d[i].u);read(d[i].v);
        lca(d[i].u,d[i].v);
        d[i].ca=LCA;
        d[i].d=dis[d[i].u]+dis[d[i].v]-2*dis[d[i].ca];
    }
    sort(d+1,d+m+1,cmp);
    int l=-1,r=d[1].d+1;
    int t,sum,ans;
    while(r-l>1)
    {
        while(top) add[S[top--]]=0;
        int mid=(l+r)>>1;
        for(t=1;t<=m;t++)
        {
            if(d[t].d<=mid) break;
            add[d[t].u]++;
            add[d[t].v]++;
            add[d[t].ca]-=2;
        }
        t--;
        sum=0,ans=0;
        for(int i=n;i>=1;i--)
        {
            v=dfs_n[i];
            if(add[v]) 
            {
                S[++top]=v;
                add[fa[0][v]]+=add[v];
            }
            if(add[v]==t)ans=Max(ans,D[v]);
        }
        ans=Max(d[1].d-ans,d[t+1].d);
        if(ans<=mid)r=mid;
        else l=mid;
    }
    printf("%d\n",r);
    return 0;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值