zoukankan      html  css  js  c++  java
  • luogu P2680 运输计划

    题目描述

    公元 2044 年,人类进入了宇宙纪元。
    
    L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。
    

    小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。

    为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
    
    在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。
    
    如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
    

    输入描述:

    第一行包括两个正整数n、m,表示L国中星球的数量及小P公司预接的运输计划的数量,星球从1到n编号。

    接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai, bi 和 ti,表示第i 条双向航道修建在ai 与bi 两个星球之间,任意飞船驶过它所花费的时间为ti。

    接下来m 行描述运输计划的情况,其中第j 行包含两个正整数uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往vj 号星球。

    输出描述:

    共 1 行,包含1个整数,表示小P的物流公司完成阶段性工作所需要的最短时间。


    LCA+二分 树链剖分也行,但是我觉得太麻烦

    二分一下那个最大时间,然后判断是否符合

    符合就可以直接返回1

    如果不符合的话,可以尝试使用一下那个把边权变为0的操作,试试用过之后能不能符合

    用树上差分来记录一条边的经过次数,判断是否存在一条边被所有超时的路径经过,并且清空后可以满足时间

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=3e5+10;
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*f;
    }
    int Next[N*2],head[N],go[N*2],w[N*2],tot;
    inline void add(int u,int v,int o){
    	Next[++tot]=head[u];head[u]=tot;go[tot]=v;w[tot]=o;
    	Next[++tot]=head[v];head[v]=tot;go[tot]=u;w[tot]=o;
    }
    int f[N][22],dep[N],dis[N],num[N];
    int n,m,cnt;
    inline void Deal(int u,int fa){
        num[++cnt]=u;dep[u]=dep[fa]+1;
    	f[u][0]=fa;
    	for(int i=1;i<=18;i++)
    	f[u][i]=f[f[u][i-1]][i-1];
    	for(int i=head[u];i;i=Next[i]){
    		int v=go[i];if(v==fa)continue;
    		dis[v]=dis[u]+w[i];
    		Deal(v,u);
    	}
    }
    inline int LCA(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=18;i>=0;i--)
    	if(dep[f[x][i]]>=dep[y])x=f[x][i];
    	if(x==y)return x;
    	for(int i=18;i>=0;i--)
    	if(f[x][i]!=f[y][i])
    	x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    struct node{
    	int u,v,dis,lca;
    }e[N];
    int delt[N];
    inline bool check(int mid){
    	memset(delt,0,sizeof(delt));
    	int cnt=0,ans=0;
    	for(int i=1;i<=m;i++)
    	if(e[i].dis>mid){
    		delt[e[i].u]++;delt[e[i].v]++;delt[e[i].lca]-=2;
    		ans=max(ans,e[i].dis-mid);
    		cnt++;
    	}
    	if(cnt==0)return 1;
    	for(int i=n;i>=1;i--)delt[f[num[i]][0]]+=delt[num[i]];
    	for(int i=2;i<=n;i++)
    	if(delt[i]==cnt&&dis[i]-dis[f[i][0]]>=ans)return 1;
    	return 0;
    }
    signed main(){
    	n=read();m=read();
    	int l=0,r=1,ans=-1;
    	for(int i=1,u,v,o;i<n;i++){
    		u=read();v=read();o=read();
    		add(u,v,o);
    	}
    	Deal(1,1);
    	for(int i=1;i<=m;i++){
    		e[i].u=read(),e[i].v=read();e[i].lca=LCA(e[i].u,e[i].v);
    		e[i].dis=dis[e[i].u]+dis[e[i].v]-2*dis[e[i].lca];
    		r=max(e[i].dis,r);
    	}
    	while(l<r){
    		int mid=(l+r)>>1;
    		if(check(mid)){
    			ans=mid;r=mid;
    		}else l=mid+1;
    	}
    	cout<<ans<<endl;
    }
    
  • 相关阅读:
    跟我学android—01.SplashActivity
    eclipse android : A project with that name already exists in the workspace
    冬吴相对论锦言佳句--0005.薄伽梵歌与“印度式管理”
    [转载]Jquery Form插件表单参数
    Form表单学习网站
    [转载]JQuery获取元素文档大小、偏移和位置和滚动条位置的方法集合
    jquery捕捉文本域输入事件
    [转载]js 遍历数组对象
    C#跳出循环的几种方法的区别
    [转载]MVC3缓存:使用页面缓存
  • 原文地址:https://www.cnblogs.com/naruto-mzx/p/11780585.html
Copyright © 2011-2022 走看看