BZOJ 4326 NOIP 2015 DAY2 T3 浅谈二分及树上差分数组DFS动态统计

14 篇文章 0 订阅
11 篇文章 0 订阅

这里写图片描述
世界真的很大
今天正值全校运动会然而却被困机房
想着写完这道题就下楼看运动会于是乎一A,老天luogu的“大凶”能奈我何?
于是还剩一点时间,所以写一下博客

看题先:

description:

公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?

input:

第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。数据保证 1≤ai,bi≤n 且 0≤ti≤1000。接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。数据保证 1≤ui,vi≤n

output:

输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。

所有时间取决于路径的最大时间,时间最小就是说最大的时间最小
最大的最小,想到二分
二分一个最大值然后check
就是说找到一条边删掉之后能让所有长度大于二分值的路径小于二分值
就是说这条边被所有路径经过
一个差分数组统计每个点头上的那条边被多少个路径经过
u++,v++,lca-=2
然后在所有这样的路径里面选一条值最大的
看所有路径的最大值减去这个值之后能不能满足条件

思路还是比较清晰而且好写好调

完整代码:

#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;

struct edge
{
    int v,last,w,u;
}ed[600010],csn[300010];

int n,m,num=0;
int head[300010],src[300010],dis[300010];
int dep[300010],anc[300010][20],mrk[300010];

bool cmp(const edge &a,const edge &b)
{
    return a.w<b.w;
}

void add(int u,int v,int w)
{
    num++;
    ed[num].v=v;
    ed[num].w=w;
    ed[num].last=head[u];
    head[u]=num;
}

void dfs(int u,int f)
{
    anc[u][0]=f;
    for(int i=1;i<=18;i++)
        anc[u][i]=anc[anc[u][i-1]][i-1];
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(v==f) continue ;
        dis[v]=dis[u]+ed[i].w,dep[v]=dep[u]+1,src[v]=ed[i].w;
        dfs(v,u);
    }
}

int lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=18;i>=0;i--)
        if(dep[anc[u][i]]>=dep[v])
            u=anc[u][i];
    if(u==v) return u;
    for(int i=18;i>=0;i--)
        if(anc[u][i]!=anc[v][i])
            u=anc[u][i],v=anc[v][i];
    return anc[u][0];
}

void dfs2(int u,int f)
{
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(v==f) continue ;
        dfs2(v,u);
        mrk[u]+=mrk[v];
    }
}

bool check(int x)
{
    memset(mrk,0,sizeof(mrk));
    int cnt=0,bns=-1;
    for(int i=m;i>=1;i--)
    {
        if(csn[i].w<=x) break ;
        cnt++;
        mrk[csn[i].u]++,mrk[csn[i].v]++;
        mrk[lca(csn[i].u,csn[i].v)]-=2;
    }
    dfs2(1,1);
    for(int i=1;i<=n;i++)
        if(mrk[i]==cnt) bns=max(bns,src[i]);
    if(csn[m].w-bns>x) return false;
    return true ;
}

int main()
{
    scanf("%d%d",&n,&m);
    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,1);
    int lf=0,rg=0,ans=0;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        csn[i].u=u,csn[i].v=v;
        csn[i].w=dis[u]+dis[v]-2*dis[lca(u,v)];
        rg=max(rg,csn[i].w);
    }
    sort(csn+1,csn+m+1,cmp);
    while(lf<=rg)
    {
        int mid=(lf+rg)>>1;
        if(check(mid))
            rg=mid-1,ans=mid;
        else lf=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/

嗯,就是这样

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值