[NOIP2015]运输计划 线段树or差分二分
[NOIP2015]运输计划
链接
luogu
好久没写博客了,水一篇波。
思路1 暴力数据结构
枚举最长链的边,删除后代价为(最长链-边权,不经过这条边的链)的最大值。
不经过某条边的最大值要用线段树维护补集。
复杂度\(O(nlog^2n)\)
思路2 二分树上差分
二分答案,删除的边为\(>mid\)的链的交集。
用树上查分维护交集。
最后在交集中找个最大的边删除就好了。
复杂度\(O(nlogn)\)
总的
思路2,复杂度小,好写,简单,细节少。
思路1,复杂度高,码量大,细节多,并不是呢么好想。
所以并不是很建议写第一种。
但他靠着树剖的小常数跑过了树上差分(至少我是这样,1.9s->1.2s)。
代码1
#include <bits/stdc++.h>
using namespace std;
const int _=5e5+7;
int read() {
	int x=0,f=1;char s=getchar();
	for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
	for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
	return x*f;
}
int n,m,ans,u[_],v[_],dsr[_],w[_];
struct node {
	int v,nxt,q,w;
}e[_<<1];
int head[_],tot;
void add(int u,int v,int q) {
	e[++tot].v=v;
	e[tot].q=q;
	e[tot].nxt=head[u];
	head[u]=tot;
}
int f[_],dep[_],siz[_],son[_],top[_],idx[_],dis[_],nb[_],cnt;
void dfs1(int u,int fa) {
	dep[u]=dep[fa]+1;
	f[u]=fa;
	siz[u]=1;
	for(int i=head[u];i;i=e[i].nxt) {
		int v=e[i].v;
		if(v==fa) continue;
		w[v]=e[i].q;
		dis[v]=dis[u]+e[i].q;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[son[u]]<siz[v]) son[u]=v;
	}
}
void dfs2(int u,int topf) {
	top[u]=topf;
	idx[u]=++cnt;
	nb[cnt]=u;
	if(!son[u]) return;
	dfs2(son[u],topf);
	for(int i=head[u];i;i=e[i].nxt) {
		int v=e[i].v;
		if(!idx[v]) dfs2(v,v);
	}
}
namespace seg_tree {
	#define ls rt<<1
	#define rs rt<<1|1
	int ma[_<<2],lazy[_];
	void tag(int rt,int val) {ma[rt]=max(ma[rt],val);lazy[rt]=max(lazy[rt],val);}
	void pushdown(int rt) {tag(ls,lazy[rt]);tag(rs,lazy[rt]);}
	void modify(int L,int R,int val,int l,int r,int rt) {
		if(L>R) return;
		if(L<=l&&r<=R) return tag(rt,val);
		int mid=(l+r)>>1;
		pushdown(rt);
		if(L<=mid) modify(L,R,val,l,mid,ls);
		if(R>mid) modify(L,R,val,mid+1,r,rs);
		ma[rt]=max(ma[ls],ma[rs]);
	}
	void dfs(int l,int r,int rt) {
		if(l==r) return void(dsr[nb[l]]=ma[rt]);
		int mid=(l+r)>>1;
		pushdown(rt);
		if(l<=mid) dfs(l,mid,ls);
		if(r>mid) dfs(mid+1,r,rs);
	}
}
int lca(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=f[top[x]];
	} return dep[x]<dep[y]?x:y;
}
void QQ(int x,int y,int val) {
	int las=n;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		seg_tree::modify(idx[x]+1,las,val,1,n,1);
		las=idx[top[x]]-1;
		x=f[top[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	seg_tree::modify(idx[x]+1,las,val,1,n,1);
	seg_tree::modify(1,idx[y],val,1,n,1);
}
int main() {
	n=read(),m=read();
	for(int i=1,x,y,q;i<n;++i) {
		x=read(),y=read(),q=read();
		add(x,y,q),add(y,x,q);
	}
	for(int i=1;i<=m;++i) {
		u[i]=read(),v[i]=read();
		if(u[i]==v[i]) m--,i--;
	}
	dfs1(1,0),dfs2(1,1);
	int id=0,ma=0;
	for(int i=1;i<=m;++i) {
		int val=dis[u[i]]+dis[v[i]]-2*dis[lca(u[i],v[i])];
		QQ(u[i],v[i],val);
		if(ma<val) id=i,ma=val;
	}
	if(!id) return printf("0\n"),0;
	seg_tree::dfs(1,n,1);
	int x=u[id],y=v[id],ans=0x3f3f3f3f;
	while(x!=y) {
		if(dep[x]<dep[y]) swap(x,y);
		ans=min(ans,max(dsr[x],ma-w[x]));
		x=f[x];
	}
	cout<<ans<<"\n";
	return 0;
}
代码2
#include <bits/stdc++.h>
using namespace std;
const int _=5e5+7;
int read() {
	int x=0,f=1;char s=getchar();
	for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
	for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
	return x*f;
}
int n,m,ans,u[_],v[_],LCA[_],len[_],the_biggest,w[_];
struct node {
	int v,nxt,q;
}e[_<<1];
int head[_],tot;
void add(int u,int v,int q) {
	e[++tot].v=v;
	e[tot].q=q;
	e[tot].nxt=head[u];
	head[u]=tot;
}
int f[_],dep[_],siz[_],son[_],dis[_],top[_],cnt;
void dfs1(int u,int fa) {
	dep[u]=dep[fa]+1,f[u]=fa,siz[u]=1;
	for(int i=head[u];i;i=e[i].nxt) {
		int v=e[i].v;
		if(v==fa) continue;
		w[v]=e[i].q;
		dis[v]=dis[u]+e[i].q;
		dfs1(v,u);
		siz[u]+=siz[v];
		if(siz[son[u]]<siz[v]) son[u]=v;
	}
}
void dfs2(int u,int topf) {
	top[u]=topf;
	if(!son[u]) return;
	dfs2(son[u],topf);
	for(int i=head[u];i;i=e[i].nxt) {
		int v=e[i].v;
		if(!top[v]) dfs2(v,v);
	}
}
int lca(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=f[top[x]];
	} return dep[x]<dep[y]?x:y;
}
int dsr[_],js;
void dfs(int u,int fa) {
	for(int i=head[u];i;i=e[i].nxt) {
		int v=e[i].v;
		if(v==fa) continue;
		dfs(v,u);
		dsr[u]+=dsr[v];
	}
}
bool check(int mid) {
	js=0;
	for(int i=0;i<=n;++i) dsr[i]=0;
	for(int i=1;i<=m;++i) {
		if(len[i]<=mid) continue;
		dsr[LCA[i]]-=2;
		dsr[u[i]]++;
		dsr[v[i]]++;
		++js;
	}
	dfs(1,0);
	int ma=0x3f3f3f3f;
	for(int i=1;i<=n;++i)
		if(dsr[i]==js) ma=min(ma,the_biggest-w[i]);
	return ma<=mid;
}
int main() {
	n=read(),m=read();
	for(int i=1,x,y,q;i<n;++i) {
		x=read(),y=read(),q=read();
		add(x,y,q),add(y,x,q);
	}
	dfs1(1,0),dfs2(1,1);
	for(int i=1;i<=m;++i) {
		u[i]=read(),v[i]=read(),LCA[i]=lca(u[i],v[i]);
		len[i]=dis[u[i]]+dis[v[i]]-2*dis[LCA[i]];
		the_biggest=max(the_biggest,len[i]);
	}
	int l=0,r=the_biggest,ans=0;
	while(l<=r) {
		int mid=(l+r)>>1;
		if(check(mid)) ans=mid,r=mid-1;
		else l=mid+1;
	} cout<<ans<<"\n";
	return 0;
}
												
											[NOIP2015]运输计划 线段树or差分二分的更多相关文章
- bzoj 4326: NOIP2015 运输计划【树链剖分+二分+树上差分】
		
常数巨大,lg上开o2才能A 首先预处理出运输计划的长度len和lca,然后二分一个长度w,对于长度大于w的运输计划,在树上差分(d[u]+1,d[v]+1,d[lca]-2),然后dfs,找出所有覆 ...
 - 洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)
		
[题目链接] [思路]: 根据题意可以明显看出,当所有任务都完成时的时间是最终的结果,也就是说本题要求,求出最小的最大值. 那这样的话就暗示了将答案二分,进行check. [check方法]: 如果说 ...
 - [NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组
		
[NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有 ...
 - BZOJ 4326:NOIP2015 运输计划(二分+差分+lca)
		
NOIP2015 运输计划Description公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所 ...
 - NOIP2015 运输计划(二分+LCA+差分)
		
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 308 Solved: 208[Submit][Status] ...
 - Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)
		
Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...
 - BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)
		
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1930 Solved: 1231[Submit][Statu ...
 - LOJ2425 NOIP2015 运输计划 【二分+LCA+树上差分】*
		
LOJ2425 NOIP2015 运输计划 LINK 题意:给你一颗树,可以将任意一条边的权值变成0,然后求m条路径的长度的最小值 思路: 先二分最后的距离ans,然后我们把路程大于ans的所有路径拿 ...
 - BZOJ 4326 NOIP2015 运输计划(树上差分+LCA+二分答案)
		
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MB Submit: 1388 Solved: 860 [Submit][Stat ...
 
随机推荐
- 在 React 组件中监听 android 手机物理返回/回退/back键事件
			
当前端页面嵌入到 webview 中运行时,有时会需要监听手机的物理返回按键事件来做一些自定义的操作. 比如我最近遇到的,在一个页面里面有批量选择的功能,当点击手机的返回键时,清除页面上的选中状态.我 ...
 - 腾讯微视:向前一步是悲壮,向后一步是绝望zz
			
“换做以往的任何一场战争,微博之战.搜索之战和电商之战——大量投入但始终不见效果,打到现在腾讯肯定已经交牌了.微视的不同之处在于,它有些悲壮,因为这是腾讯最不想交出的一张牌.” 文 | <财经& ...
 - Linux shell自动读mongo数据、远程获取文件大小示例脚本
			
1.示例1 功能:对mongoDB导出数据,根据sid的不同状态进行统计 技术点:shell bash 读写文件.字符串截取.函数.用多个文件提到的map.grep查找并赋值给变量 #!/bin/b ...
 - 移动端BUG
			
1.解决 Android 系统 设置line-height和height相同,文字却偏上显示(pc端和ios都显示ok) 行高设置为 normal 则可以解决. 然后高度通过padding填充 lin ...
 - C# WinForm自定义通用分页控件
			
大家好,前几天因工作需要要开发一个基于WinForm的小程序.其中要用到分页,最开始的想法找个第三方的dll用一下,但是后来想了想觉得不如自己写一个玩一下 之前的web开发中有各式各样的列表组件基本都 ...
 - PIE SDK水体指数法
			
1.算法功能简介 单波段阈值法是通过选择某单一波段为判识参数,这一波段往往是水体特征最明显而其它地物相对不太突出的波段(如近红外波段和中红外波段),然后再划定阈值来确定水体信息.该方法主要是利用水体在 ...
 - jenkins19年最新最管用的汉化
			
今天准备学学jenkins ,官方下载了一个最新版本,发现是英文版,网上找个许多汉化方式,几乎都是一种,下载插件 :Locale plugin ....很尴尬,下载完了还是没有汉化 ,是不是jenki ...
 - shiro加密算法
			
第一节的时候我介绍过,shiro有很多加密算法,如md5和sha,而且还支持加盐,使得密码的解析变得更有难度,更好的保障了数据的安全性. 这里我们要介绍的是md5算法,因为比较常用.首先我们来看看md ...
 - uni-app学习(六)好用的插件4
			
1. uni-app学习(六)好用的插件4 1.1. QQ音乐模板 点击这里 示例 1.2. 画廊(ynGallery)组件 点击这里 看起来不错的 示例 1.3. 评价模板 学到个动画用法 imag ...
 - SAP S4HANA BP事务代码初始界面的ROLE和Grouping配置
			
SAP S4HANA BP事务代码初始界面的ROLE和Grouping配置 SAP S/4 HANA系统里,创建供应商不再使用MK01/FK01/XK01等事务代码,而是使用BP事务代码. BP事务代 ...