zoukankan      html  css  js  c++  java
  • 洛谷P2680 运输计划——树上差分

    题目:https://www.luogu.org/problemnew/show/P2680

    久违地1A了好高兴啊!

    首先,要最大值最小,很容易想到二分;

    判断当前的 mid 是否可行,需要看看有没有去掉一条边使满足的方案;

    这就需要树上差分来找出每条边被几个超过 mid 的路线覆盖;

    若有一条边正好被所有超过 mid 的路线覆盖,且去掉它之后最大的路线也能满足,就是可行的。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int const maxn=3e5+5;
    int n,m,head[maxn],ct,cnt,st[maxn],ed[maxn],tag[maxn],lca[maxn],len[maxn];
    int h[maxn],ans,mx,f[maxn][20],dep[maxn],l,r,mid;
    bool flag;
    struct N{
        int to,next,w;
        N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {}
    }edge[maxn<<1];
    void add(int x,int y,int z){edge[++ct]=N(y,head[x],z); head[x]=ct;}
    void init(int x,int fa)
    {
        f[x][0]=fa; dep[x]=dep[fa]+1;
        for(int i=1;i<=18;i++)f[x][i]=f[f[x][i-1]][i-1];
        for(int i=head[x],u;i;i=edge[i].next)
            if((u=edge[i].to)!=fa) h[u]=h[x]+edge[i].w, init(u,x);
    }
    int LCA(int x,int y)
    {
        if(dep[x]<dep[y])swap(x,y);
        int k=dep[x]-dep[y];
        for(int i=0;i<=18;i++)
            if(k&(1<<i))x=f[x][i];
        for(int i=18;i>=0;i--)
            if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
        if(x==y)return x;
        return f[x][0];
    }
    void dfs(int x)
    {
        for(int i=head[x],u;i;i=edge[i].next)
        {
            if((u=edge[i].to)==f[x][0])continue;
            dfs(u); if(flag)return;
            if(tag[u]==cnt && mx-edge[i].w<=mid)flag=1;
            tag[x]+=tag[u];
        }
    }
    bool ck()
    {
        cnt=0; flag=0;
        memset(tag,0,sizeof tag);
        for(int i=1;i<=m;i++)
            if(len[i]>mid)
            {
                tag[st[i]]++; tag[ed[i]]++;
                tag[lca[i]]-=2; cnt++;
            }
        dfs(1);
        return flag;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,x,y,z;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z); add(y,x,z);
        }
        init(1,0);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&st[i],&ed[i]);
            lca[i]=LCA(st[i],ed[i]);
            len[i]=h[st[i]]+h[ed[i]]-2*h[lca[i]];
            mx=max(mx,len[i]);
        }
        l=0,r=mx;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(ck())ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Dom对象和jQuery对象区别 jQuery对象转换为Dom对象、、Dom对象转换为jquery对象
    jquery 1,2,3三个版本的下载、区别/以及jquery使用步骤,jQuery入口函数
    2021年3月4日 第一周开课博客
    2021年3月3日
    2021年3月2日
    2021年2月24日 记账本开发07
    2021年2月23日 记账本开发06
    2021年2月22日 记账本开发05
    程序员修炼之道读书笔记03
    2021年2月21日 记账本开发04
  • 原文地址:https://www.cnblogs.com/Zinn/p/9218761.html
Copyright © 2011-2022 走看看