运输计划(题解)(Noip2015)
运输计划(题解)(Noip2015)
二分答案+树上差分
树上差分其实不难,只是名字高大尚,可以学一下:Eternal风度的树上差分
本人博客里也总结了一些其他的知识供大家学习:Eternal风度的博客
具体解答
至于这是怎么想到的,一步一步来:
1.n有300000,不可能暴力枚举每一条边
2.因为我们要使运输时间的最大值最小,所以,考虑二分答案(做多了之后的习惯(其实也就是突然的灵感,不是必然......))
3.既然二分了答案,暂且把我们二分的答案变量名叫 lim ,考虑On的check():
- 想到每次把超过lim(跑LCA求运输计划的时间)的运输计划全部要考虑删边(显然),并且这些计划都必须要删一条公共边(也是显然,加虫洞就相当于把边权变为0,姑且叫做删边把)
- 这就可以考虑差分了,把超过lim的计划全部差分进去,统计一下差分数组,枚举所有计划都经过的边(也就是差分数组==超过lim的计划数),看看最大的运输代价减去这个边权(相当于把它变为0,显然)是否小于lim(如果最大值都小于lim了,所有的都小于lim了)
上代码:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<ctime>
#include<queue>
#include<stack>
#define rg register
#define lst long long
#define N 300050
using namespace std;
int n,m,cnt,ans,maxn,le,ri;
struct EDGE{
    int to,v,nxt;
}edge[N<<1];
struct ROAD{
    int fm,to,v;
}road[N];
int head[N],back[N];
int cf[N];
int deep[N],fa[N];
int f[N][25],g[N][25];
inline int read()
{
    rg int s=0,m=1;rg char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')m=-1,ch=getchar();
    while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    return s*m;
}
inline void add(rg int p,rg int q,rg int o)
{
    edge[++cnt].to=q,edge[cnt].v=o;
    edge[cnt].nxt=head[p];
    head[p]=cnt;
}
void dfs(rg int now,rg int fm,rg int dep,rg int s)//dfs预处理倍增LCA
{
    fa[now]=fm,deep[now]=dep;
    f[now][0]=fm;g[now][0]=s;
    for(rg int i=1;i<=20;++i)
    {
        f[now][i]=f[f[now][i-1]][i-1];
        g[now][i]=g[f[now][i-1]][i-1]+g[now][i-1];
    }
    for(rg int i=head[now];i;i=edge[i].nxt)
    {
        rg int qw=edge[i].to;
        if(qw!=fm)
        {
            back[qw]=i;
            dfs(qw,now,dep+1,edge[i].v);
        }
    }
}
inline int LCA(rg int x,rg int y,rg int op)//倍增跳LCA
{
    rg int res=0;
    if(deep[x]<deep[y])swap(x,y);
    while(deep[x]>deep[y])//跳到同样深度
        for(rg int i=20;i>=0;--i)
            if(deep[f[x][i]]>=deep[y])res+=g[x][i],x=f[x][i];
    while(x!=y)
    {
        for(rg int i=20;i>=0;--i)
            if(f[x][i]!=f[y][i])
                res+=g[x][i]+g[y][i],x=f[x][i],y=f[y][i];
        if(fa[x]==fa[y])res+=g[x][0]+g[y][0],x=y=fa[x];
    }
    if(!op)return res;
    else return x;
}
inline void Insert(rg int p,rg int q)//差分
{
    rg int lca=LCA(p,q,1);
    cf[p]++,cf[q]++,cf[lca]-=2;
}
void sum(rg int now)//统计差分数组
{
    for(rg int i=head[now];i;i=edge[i].nxt)
    {
        rg int qw=edge[i].to;
        if(qw!=fa[now])
        {
            sum(qw);
            cf[now]+=cf[qw];
        }
    }
}
inline int check(rg int lim)//如解析,check()
{
    rg int ss=0,Max=0;
    for(rg int i=1;i<=n;++i)cf[i]=0;
    for(rg int i=1;i<=m;++i)
    {
        if(road[i].v>lim)
        {
            Max=max(Max,road[i].v);
            ss++,Insert(road[i].fm,road[i].to);
        }
    }
    sum(0);
    for(rg int i=1;i<=n;++i)
        if(cf[i]==ss&&Max-edge[back[i]].v<=lim)return 1;
    return 0;
}
int main()
{
    n=read(),m=read();
    for(rg int i=1;i<n;++i)
    {
        rg int p=read(),q=read(),o=read();
        add(p,q,o),add(q,p,o);
    }
    //读入边的信息
    dfs(1,0,1,0);
    for(rg int i=1;i<=m;++i)
    {
        rg int p=read(),q=read();
        road[i].fm=p,road[i].to=q,road[i].v=LCA(p,q,0);
        ri=max(ri,road[i].v);
    }
    add(0,1,0);//没事干加了一个 0->1 的边,感觉比较踏实(0的父亲是1)...无语...
    while(le<=ri)//二分
    {
        rg int mid=(ri+le)>>1;
        if(check(mid))ans=mid,ri=mid-1;
        else le=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}
运输计划(题解)(Noip2015)的更多相关文章
- [NOIP2015 提高组] 运输计划题解
		题目链接:P2680 [NOIP2015 提高组] 运输计划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 看了好长时间题解才终于懂的,有关lca和二分答案的题解解释的不详细,一时 ... 
- NOIP2015运输计划题解报告
		这题在洛谷上可以找到提交 P2680运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航 ... 
- [NOIP2015]运输计划 题解
		题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条 航道连通了 L 国的所有星球. 小 P 掌管一 ... 
- luoguP2680 运输计划  题解(二分答案+树上差分)
		P2680 运输计划 题目 这道题如果是看的我的树上差分来的,那么肯定一看题目就可以想到树上差分. 至于这是怎么想到的,一步一步来: 1.n有300000,不可能暴力枚举每一条边 2.因为我们要使运 ... 
- 题解 [NOIP2015]运输计划
		题解 [NOIP2015]运输计划 题面 解析 首先肯定是要求出每条路径的长度. 这个用节点到根的前缀和就行了(一开始脑抽写了个线段树...) 然后有一个显然的类似贪心的想法, 就是你改造的边肯定在最 ... 
- NOIP2015 运输计划(bzoj4326)
		4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 886 Solved: 574[Submit][Status] ... 
- [BZOJ4326][codevs4632][codevs5440][UOJ#150][NOIP2015]运输计划
		[BZOJ4326][codevs4632][codevs5440][UOJ#150][NOIP2015]运输计划 试题描述 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n− ... 
- [NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组
		[NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有 ... 
- 【NOIP2015】运输计划
		[NOIP2015]运输计划 标签: 树上差分 LCA 二分答案 Description 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星 ... 
随机推荐
- vue  组件间传值方式
			/* 父组件给子组件传值 1.父组件调用子组件的时候 绑定动态属性 <v-header :title="title"></v-header> 2.在子组件里 ... 
- less:运算
			less中的运算 -任何数字.颜色或者变量都可以参加运算,运算应该被包裹在括号中. -例如:+-*. @width: 30px; .box { width: (20 + 5) * @width; } ... 
- 使用Node,Vue和ElasticSearch构建实时搜索引擎
			(译者注:相关阅读:node.js,vue.js,Elasticsearch) 介绍 Elasticsearch是一个分布式的RESTful搜索和分析引擎,能够解决越来越多的用例. Elasticse ... 
- myeclipce注册
			今天提示MyEclipse Trial Expired,如何手动获取MyEclipse 注册码! 1.建立JAVA Project,随便命名,只要符合规则就行. 2.在刚刚建好的Project右击sr ... 
- spring boot 1.视图解析器,2.开启静态资源访问
			1.spring boot 视图解析器 #视图解析器 #前缀spring.mvc.view.prefix=/pages/ #后缀..jsp.dospring.mvc.view.suffix=.jsp ... 
- WinForm、WPF、ASP.NET窗口生命周期
			https://blog.csdn.net/s_521_h/article/details/73826928 
- 前端开发本地存储之cookie
			1.cookie cookie是纯文本,没有可执行代码,是指某些网站为了辨别用户身份.进行 session 跟踪而储存在用户本地终端(浏览器)上的数据(通常经过加密).当用户访问了某个网站的时候,我们 ... 
- 170814关于Cookie的知识点
			1.会话控制 Http协议 Http协议两个缺陷: 1.HTTP协议是纯文本的 2.HTTP协议是无状态的 服务器不能简单的通过HTTP协议来区分多次请求是否发自同一个用户 虽然通过H ... 
- Android 一键分享功能简单实现
			import java.io.File;import java.util.ArrayList;import java.util.List; import android.content.Context ... 
- SSL异常javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
			jdk 7 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html jdk 8 http: ... 
