zoukankan      html  css  js  c++  java
  • 洛谷 2680 (NOIp2015) 运输计划

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

    因为是最长的时间最短,所以二分!

    离线LCA可以知道路径长度。每次只看超过二分值的路径。

    原本的想法是遍历一下每条超过二分值的路径,找出“去掉它就能使该路径合法”的那些边,打上标记,最后找到有k个标记的边就能行。

    但有点不合适。不需要找出“……”的那些边,而把所有该路径上的边都打上标记,最后找到有k个标记的边的时候判断一下去掉它能不能行。

      这样就像均摊了复杂度一样。反正最后都得遍历树,可以那时多做一点、之前少做一点,使时间更好。

    注意给边打标记是把它落在它下面的那个点上。而且是LCA的地方-2,和给点打标记不同。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int N=3e5+5;
    int n,m,head[N],xnt,cs[N],bh[N],l,r,mx,fa[N],hd[N],xt,dis[N],nw,mid,ans;
    bool vis[N],flag;
    struct Ques{
        int dis,x,y,lca;
    }a[N];
    struct Edge{
        int next,to,w;
        Edge(int n=0,int t=0,int w=0):next(n),to(t),w(w) {}
    }edge[N<<1],ed[N<<1];
    void add(int x,int y,int z)
    {
        edge[++xnt]=Edge(head[x],y,z);head[x]=xnt;
        edge[++xnt]=Edge(head[y],x,z);head[y]=xnt;
    }
    void ad(int x,int y,int z)
    {
        ed[++xt]=Edge(hd[x],y,z);hd[x]=xt;
        ed[++xt]=Edge(hd[y],x,z);hd[y]=xt;
    }
    int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);}
    bool cmp(Ques a,Ques b){return a.dis>b.dis;}
    void tarjan(int cr,int f)
    {
        vis[cr]=1;
        for(int i=hd[cr],v;i;i=ed[i].next)
            if(vis[v=ed[i].to])
            {
                int k=ed[i].w,lc=find(v);
                a[k].lca=lc;a[k].dis=dis[cr]+dis[v]-2*dis[lc];
                mx=max(mx,a[k].dis);
            }
        for(int i=head[cr],v;i;i=edge[i].next)
            if((v=edge[i].to)!=f)
            {
                bh[v]=i;
                dis[v]=dis[cr]+edge[i].w;
                tarjan(v,cr);fa[v]=cr;
            }
    }
    void solve(int cr)
    {
        cs[a[cr].x]++;cs[a[cr].y]++;cs[a[cr].lca]-=2;
    }
    int dfs(int cr,int f)
    {
        int ret=cs[cr];
        for(int i=head[cr],v;i;i=edge[i].next)
            if((v=edge[i].to)!=f)
            {
                ret+=dfs(v,cr);if(flag)return 0;
            }
        if(ret==nw&&mx-edge[bh[cr]].w<=mid)flag=1;
        return ret;
    }
    int main()
    {
        scanf("%d%d",&n,&m);int x,y,z;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);add(x,y,z);
            fa[i]=i;
        }
        fa[n]=n;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);ad(a[i].x,a[i].y,i);
        }
        tarjan(1,0);sort(a+1,a+m+1,cmp);r=mx;
        while(l<=r)
        {
            mid=((l+r)>>1);memset(cs,0,sizeof cs);
            for(nw=1;nw<=m&&a[nw].dis>mid;nw++)solve(nw);
            nw--;flag=0;dfs(1,0);
            if(flag)ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Android无线测试之—UiAutomator UiSelector API介绍之四
    Android无线测试之—UiAutomator UiSelector API介绍之三
    Android无线测试之—UiAutomator UiSelector API介绍之二
    网页抓取- 3
    VC 6.0 LNK2005 错误 处理
    抓取网页(3)之部分工程文件
    网页抓取 (2)
    网页抓取总结(一)
    nyoj-291 互素数个数 欧拉函数
    nyoj-257 郁闷的C小加(一) 前缀表达式变后缀
  • 原文地址:https://www.cnblogs.com/Narh/p/9218679.html
Copyright © 2011-2022 走看看