• [NOIP 2005] 运输计划


    link

    这是一道假的图论

    思维难度很低,代码量偏高

    就是一道板子+二分

    树上差分就AC了

    注意卡常即可

    二分枚举答案x,为时间长度

    将每一个长度大于x的计划链长记录下来(有几个,总需要减少多少长度)

    在树上跑一跑即可

    树上差分就将u,vv权值+1,lca(u,v)-2即可

    dp[i]:为子树权值和,也是i上面道路有几条路径覆盖

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int f=1,ans=0;char c;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    int n,m;
    struct node{
        int u,v,w,nex;
    }x[600001];
    int deep[300001],vt[300001],dis[300001],fa[300001][21],head[300001],cnt=1;
    void add(int u,int v,int w)
    {
        x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
    }
    void dfs(int f,int fath,int DIS)
    {
        deep[f]=deep[fath]+1;
        dis[f]=DIS;
        fa[f][0]=fath;
        for(int i=1;(1<<i)<=deep[f];i++) fa[f][i]=fa[fa[f][i-1]][i-1];
        for(int i=head[f];i;i=x[i].nex)
        {
            if(x[i].v==fath) continue;
            vt[x[i].v]=x[i].w;
            dfs(x[i].v,f,DIS+x[i].w);
        }
        return;
    }
    int lca(int u,int v)
    {
        if(deep[u]<deep[v]) swap(u,v);
        for(int i=19;i>=0;i--) 
            if(deep[u]-(1<<i)>=deep[v]) u=fa[u][i];
        if(u==v) return u;
        for(int i=19;i>=0;i--)
        {
            if(fa[u][i]==fa[v][i]) continue;
            u=fa[u][i],v=fa[v][i];
        }return fa[u][0];
    }
    struct node1{
        int x,y,lca,dis;
    }s[300001];
    int l,r,mid,dp[300001];
    void dp_tree(int f,int fath)
    {
        for(int i=head[f];i;i=x[i].nex)
        {
            if(x[i].v==fath) continue;
            dp_tree(x[i].v,f);
            dp[f]+=dp[x[i].v];
        }
        return;
    }
    bool check(int st)
    {
        memset(dp,0,sizeof(dp));
        int tot=0,maxn=0;
        for(int i=1;i<=m;i++)
        {
            if(s[i].dis>st)
            {
                tot++;
                dp[s[i].x]++,dp[s[i].y]++,dp[s[i].lca]-=2;
                maxn=max(maxn,s[i].dis-st);
            }
        }
        dp_tree(1,0);
        for(int i=2;i<=n;i++) 
            if(dp[i]==tot&&vt[i]>=maxn) return 1;
        return 0;
    }
    int data=2<<30-1;
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<n;i++)
        {
            int u=read(),v=read(),w=read();
            add(u,v,w),add(v,u,w);
        }
        dfs(1,0,0);
        for(int i=1;i<=m;i++)
        {
            s[i].x=read(),s[i].y=read();
            s[i].lca=lca(s[i].x,s[i].y);
            s[i].dis=dis[s[i].x]+dis[s[i].y]-(dis[s[i].lca]<<1);
            r=max(r,s[i].dis);
        }
        while(l<=r)
        {
            mid=l+r>>1;
            if(check(mid)) data=min(data,mid),r=mid-1;
            else l=mid+1;
        }
        printf("%d",data);
    }
    View Code
  • 相关阅读:
    前端安全之XSS攻击
    从JavaScript执行上下文理解变量提升
    em、rem和px的区别
    纯CSS实现幻灯片效果
    小白在使用ISE编写verilog代码综合时犯得错误及我自己的解决办法
    结构体指针中的一点困惑
    xilinx fpga中块ram的使用——简单双端口ram的使用
    在模块中如何去写输出标志位的程序
    学习感悟
    xilinx fpga 生成3*3窗口
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/9720557.html
Copyright © 2020-2023  润新知