运输计划[做题笔记]



挺难绷的。。。

题意

概括:给定 \(n\) 个节点的树和 \(n-1\) 条边的权值,现在可以将一条边的权值改为 \(0\) 。找出一条边,使得将这条边权值赋为 \(0\) 时,\(T\) 组节点 \(u,v\) 之间的距离最大值最小,输出最小值。

思路分析

一开始想假了,天真的以为被 \(T\) 组节点 \(u,v\) 覆盖的次数最多,且权值较大的边就是要删去的边,\(38\)分,查题解才知道是二分答案。

不过确实,求最大值最小,的确是要二分的。若 \(t1<t2\) ,且 \(t1\) 合法,那么\(t2\)当然合法,单调性不就出来了?明确要二分后,先预处理出 \(T\) 组节点 \(u,v\) 的 \(LCA\) 和距离 \(len\) ,那么答案二分的区间就是 \([0,MAXLEN]\) 。

    二分答案的精髓是什么?是check()函数
————miaomiao

首先为了不产生歧义,我们定义节点\(u,v\)之间的树上路径为链,路径长为链长;下文的边即为树的边。

那么,对于当前 \(check\) 的 \(x\),有:

  • \(First\),要使 \(x\) 合法,那么删去这条边后,所有链长均小于等于 \(x\)
  • \(Second\),要找出这条边,首先要枚举所有的链长 \(len\) ,记录比\(x\)大的个数 \(sum\) ,并将这些链在树上差分。如果有一条边被上述链同时覆盖,显然这就是我们要赋\(0\)的最优边(当然可能存在多条,显然要取边权最大的 \(max\_ len\))
  • \(Third\),用 \(MAXLEN-max\_ len\),这是赋\(0\)后的最长链的长,如果结果\(<=x\),显然\(x\)合法(最长边都满足,底下那些小弟就更不用说了)

嗯,一切都这么美妙,但如果不会树上差分,不就祭了?那么,首先我们要会正常的差分 (不会建议回普及组重修),说白了差分就是一个反映相对大小的东西

如果你觉得一个知识点很简单,下一步,把它挂到树上去。
————波波

定义一个差分数组 \(spx[\ ]\) 。对于这种求边被覆盖的次数,首先边权肯定都是\(0\),边上差分很不方便,那么我们把边权下放到点上,\(spx_i\) 表示 \(i\) 和 \(i\) 的父节点之间的边的差分,当我们要将 \(u_i,v_i\) 这条链放到覆盖到树上,显然我们只需要修改 \(u_i\) 节点, \(v_i\) 节点和 \(LCA(u_i,v_i)\) 的差分,\(spx[u_i]\)++, \(spx[v_i]\)++, \(spx[lca(u_i,v_i)]\)-=\(2\)。为啥是\(2\)?很显然我们将链 \((u_i,v_i)\) 分成了 \((u_i,lca_i)\) 和 \((v_i,lca_i)\) 两条链进行差分,显然要减\(2\)。

差分完之后,实际的边权\(k\)就是它的子树中差分数组的和(类似于正常差分中前缀和),这可以通过一遍\(dfs\)实现。

服了,求\(LCA\)必须用\(tarjan\),倍增过不了,卡\(95\)……挺难崩的,现学\(tarjan\)求\(LCA\)(狂\(D\)不止)不过\(tarjan\)求确实比倍增快,\(O(n+m)\) 比 \(O(n\ log_2n)\) 友好多了

呃,如果有dalao发现我的代码和您差不多,那我可能是贺的您的,别D我(逃,%%%

\(AC \ code\)

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define N 300010
#define int long long
int n,m;int ans;
struct EDGE{
int next,to,t;
}e[N<<1],d[N<<1];//q是存原树,d是存查询的T组u,v构成的树,为了tarjan求LCA而生
int spx[N];//这是差分数组,数组名只是数组名,没啥特殊含义
int he[N],tot;
int hd[N];
int edge[N];//树上差分,将边权下放到点上进行差分,edge[i]表示节点i代表的边
int MAXLEN;//最长路径
struct SOLVE{
int u,v,lca,len;
}q[N];//这个结构体存的是T条链(ui,vi)的信息 inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
return f*x;
}
void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
return;
} void add(int u,int v,int t)
{
tot++;
e[tot].to=v;
e[tot].next=he[u];
he[u]=tot;
e[tot].t=t;
return ;
}
void add_d(int u,int v)
{
tot++;
d[tot].to=v;
d[tot].next=hd[u];
hd[u]=tot;
return;
}
int fa[N];//并查集
int dis[N];//前缀和方便计算链长
int find(int x)
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
bool f[N];
void tarjan(int x,int pre)//tarjan求LCA
{
int y;
for(int i=he[x];i>0;i=e[i].next)
{
y=e[i].to;
if(y!=pre)
{
edge[y]=i;
dis[y]=dis[x]+e[i].t;
tarjan(y,x);
int fa_x=find(x);
int fa_y=find(y);
if(fa_x!=fa_y)
fa[fa_y]=fa_x;
f[y]=1;
}
}
for(int i=hd[x];i>0;i=d[i].next)
{
y=d[i].to;
if(f[y]){
int now=(i+1)>>1;//因为存的是双向边,所以第i条边对应的编号为(i+1)/2
q[now].lca=find(y);
q[now].len=dis[x]+dis[y]-2*dis[q[now].lca];
MAXLEN=max(MAXLEN,q[now].len);
}
}
}
int sum,max_len;//sum代表比当前check的x大的边的个数,即需要减小的边数
void dfs_spx(int x,int pre)//树上差分
{
int y;
for(int i=he[x];i>0;i=e[i].next)
{
y=e[i].to;
if(y!=pre)
{
dfs_spx(y,x);
spx[x]+=spx[y];
}
}
if(spx[x]==sum)//如果该边能够让所有链都覆盖
max_len=max(max_len,e[edge[x]].t);
}
bool check(int x)
{
for(int i=0;i<=n;i++) spx[i]=0;
sum=0;max_len=0;
for(int i=1;i<=m;i++)
{
if(q[i].len>x)
{
sum++;
spx[q[i].u]++;
spx[q[i].v]++;
spx[q[i].lca]-=2;
}
}
dfs_spx(1,0);
if(MAXLEN-max_len<=x)
return 1;
return 0;
} signed main()
{
n=read();m=read();
for(int i=1;i<n;++i)
{
int a,b,c;
a=read(),b=read(),c=read();
add(a,b,c);add(b,a,c);
}
tot=0;
for(int i=1;i<=n;++i) fa[i]=i;//并查集初始化
for(int i=1;i<=m;++i)
{
int u,v;
u=read(),v=read();
q[i].u=u;q[i].v=v;
add_d(u,v);add_d(v,u);
}
tarjan(1,0);
int st=0,ed=MAXLEN;
while(st<ed)
{
int mid=(st+ed)>>1;
if(check(mid)) ed=ans=mid;
else st=mid+1;
}
write(ans);
return 0;
}

[noip2015]运输计划(LCA,二分)的更多相关文章

  1. NOIP2015 运输计划(二分+LCA+差分)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 308  Solved: 208[Submit][Status] ...

  2. BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)

    NOIP2015 运输计划Description公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所 ...

  3. LOJ2425 NOIP2015 运输计划 【二分+LCA+树上差分】*

    LOJ2425 NOIP2015 运输计划 LINK 题意:给你一颗树,可以将任意一条边的权值变成0,然后求m条路径的长度的最小值 思路: 先二分最后的距离ans,然后我们把路程大于ans的所有路径拿 ...

  4. bzoj4326: NOIP2015 运输计划(二分+LCA+树上差分)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4326 题目大意:有一颗含有n个顶点的树,每两个点之间有一个边权,现在有m个运输计划,每个 ...

  5. [luogu2680] 运输计划 (lca+二分+树上差分)

    传送门 Description Input Output 一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间. Sample Input 6 3 1 2 3 1 6 4 3 1 7 4 3 ...

  6. NOIP2015运输计划(二分答案)

    题目描述 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球. 小P掌管一家物流公司,该公司有很多个运输计划,每 ...

  7. bzoj 4326: NOIP2015 运输计划(二分+树链剖分)

    传送门 题解: 树链剖分快速求解任意两点间的路径的权值和: 然后,二分答案: 此题的难点是如何快速求解重合路径? 差分数组可以否??? 在此之前先介绍一下相关变量: int fa[maxn]; int ...

  8. luogu2680 [NOIp2015]运输计划 (tarjanLca+二分答案+树上差分)

    我们先不会就二分一下答案,设它是x,我们要判断它能不能满足 为了满足这个答案,我们就要让原本路径长度大于x的所有路径都经过某条边,而且这条边还要大于等于最长的路径-x 于是运用树上差分的思想,对于所有 ...

  9. 2018.09.26 bzoj4326: NOIP2015 运输计划(二分+树上差分)

    传送门 简单树上操作. 先转边权为点权. 显然所有的询问操作对应的路径会有一些交点,那么我们可以直接二分答案,对于所有大于二分值的询问用树上差分维护,最后dfs一遍每个点被覆盖了几次,当前情况合法当且 ...

  10. [NOIp2015]运输计划 (二分 $+$ 树上差分)

    #\(\mathcal{\color{red}{Description}}\) \(Link\) 在一棵带有边权的树上,可以选择使一条边权为零.然后对于所有\(M\)条链,使其链长最大值最小. #\( ...

随机推荐

  1. ssh原理及使用场景

    用过linux系统的朋友,基本肯定会用过ssh.因为大部分的linux登录都是通过ssh将进行登录,除非你用的是类似windows的桌面版. 一.什么是SSH SSH 为 Secure Shell 的 ...

  2. OGG常用运维命令

    1. 管理(MGR)进程命令 INFO MANAGER         返回有关管理器端口和进程id的信息. START MANAGER       开启管理进程 STATUS MANAGER    ...

  3. Codeforces Round #847 (Div. 3) A-G

    比赛链接 A 题意 判断输入字符串与 \(\pi\) 的最长前缀匹配,不超过 \(30\) 位. 题解 知识点:模拟. 抄样例最后一个 \(30\) 都正确的,直接匹配. 时间复杂度 \(O(1)\) ...

  4. 【Unity3D】基于AssetBundle实现资源热更新

    1 前言 ​ Unity3D 本地资源一般放在 Resources 目录下,但是 Resouces 文件夹的大小不能超过 2G,使用 AssetBundle 管理资源可以解决 Resources 文件 ...

  5. Js实用小技巧

    Js实用小技巧 这是一份Js实用小技巧,也可以是一份Js挨打小技巧,下面的一系列操作虽然能够在一定程度上使代码更加简洁,但是在缺少注释的情况下会降低可读性,所以需要谨慎使用这些黑魔法. 位元算 取整 ...

  6. spring boot携手echarts实现双柱状图实战

    说明 最近做了个图书管理系统,里面有个模块是统计最近一周借书和还书的情况. 设计为柱状图模式展现,自然需要用到echarts. 实现效果 开发步骤 1.页面和JS <!DOCTYPE html& ...

  7. Java中交换2个变量的三种方式

    这一题是我之前找Java工作时的笔试题,比较有代表性,拿出来和大家分享. package com.dylan.practice.interview; /** * 交换2个整形变量的几种方式 * * @ ...

  8. python项目vscode配置

    最近由pycharm切到VScode, 记录一下项目的通用配置; 在项目目录建一个.vscode的文件夹分别创建三个文件 lunch.json python运行配置 settings.json vsc ...

  9. OpenCV开发笔记(五十八):红胖子8分钟带你深入了解图像的矩(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  10. Kotlin 协程二 —— 通道 Channel

    目录 一. Channel 基本使用 1.1 Channel 的概念 1.2 Channel 的简单使用 1.3 Channel 的迭代 1.4 close 关闭 Channel 1.5 Channe ...