NOIP2018 旅行 和 赛道修建
填很久以前的坑。
旅行
给一棵 n 个点的基环树,求字典序最小的DFS序。
n ≤ 5000
题解
O(n2) 做法非常显然,枚举断掉环上哪条边然后贪心即可。当然我去年的骚操作只能得88分。
O(n log n) 做法,推荐duoluoluo的博客。
环上要删的边是固定的,我们在环上走的时候,只有当其出边连向的点中,环上点编号最大,且比回溯到父亲后第一个走的点还大,这时候才回溯,其他时候就正常跑DFS。
#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
	T x=0,w=1;char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*w;
}
template<class T> T read(T&x){
	return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;
co int N=500000+10;
int n,m;
struct edge {int x,y;}eg[N*2];
il bool operator<(co edge&a,co edge&b){
	return a.y<b.y;
}
vector<int> to[N];
namespace T1{
	int vis[N],ans[N],num;
	void dfs(int x){
		vis[x]=1,ans[++num]=x;
		for(int i=0;i<(int)to[x].size();++i){
			int y=to[x][i];
			if(!vis[y]) dfs(y);
		}
	}
	void main(){
		dfs(1);
		for(int i=1;i<=n;++i) printf("%d ",ans[i]);
	}
}
namespace T2{
	int circle,f[N],rings[N];
	int vis[N],ans[N],num;
	int comp,recur;
	void dfs_ring(int x,int fa){
		if(circle) return;
		if(!f[x]) f[x]=fa;
		else if(f[x]!=fa){
			for(;fa!=x;fa=f[fa]) rings[fa]=1;
			rings[x]=1,circle=1;
			return;
		}
		for(int i=0;i<(int)to[x].size();++i){
			int y=to[x][i];
			if(y==fa) continue;
			dfs_ring(y,x);
		}
	}
	void dfs_ans(int x){
		vis[x]=1,ans[++num]=x;
		if(!rings[x]){
			for(int i=0;i<(int)to[x].size();++i){
				int y=to[x][i];
				if(vis[y]) continue;
				dfs_ans(y);
			}
			return;
		}
		int found=0;
		for(int i=0;i<(int)to[x].size();++i){
			if(recur) break;
			int y=to[x][i];
			if(vis[y]) continue;
			if(rings[y]){
				int j=i+1;
				while(j<(int)to[x].size() and vis[to[x][j]]) ++j;
				if(j<(int)to[x].size()) comp=to[x][j];
				else if(y>comp) found=1,recur=1;
				break;
			}
		}
		for(int i=0;i<(int)to[x].size();++i){
			int y=to[x][i];
			if(vis[y]) continue;
			if(rings[y] and found) continue;
			dfs_ans(y);
		}
	}
	void main(){
		dfs_ring(1,1);
		comp=INT_MAX,dfs_ans(1);
		for(int i=1;i<=n;++i) printf("%d ",ans[i]);
	}
}
int main(){
	read(n),read(m);
	for(int i=1;i<=m;++i){
		int x=read<int>(),y=read<int>();
		eg[2*i-1]=(edge){x,y},eg[2*i]=(edge){y,x};
	}
	sort(eg+1,eg+2*m+1);
	for(int i=1;i<=2*m;++i) to[eg[i].x].push_back(eg[i].y);
	if(m==n-1) T1::main();
	else T2::main();
	return 0;
}
赛道修建
给一棵 n 个点带权无向树,要求找出 m 条不相交的简单路径,使得路径长度最小值最大。
n ≤ 50000
题解
二分答案判可行性。推荐owencodeisking的博客。
对于每个结点,把所有传上来的值 val 放进一个 multiset ,其实这些值对答案有贡献就两种情况:
- val≥k
- vala+valb≥k
那么第一种情况可以不用放进 multiset,直接答案 +1 就好了。第二种情况就可以对于每一个最小的元素,在 multiset 中找到第一个 ≥k的数,将两个数同时删去,最后把剩下最大的值传到那个结点的父亲
我出考场后想为什么这种解法是正确的,有没有可能对于有些情况直接传最大的数会使答案更大?
当然不会。这个数即使很大也只能对答案贡献加 1,在其没传上去的时候可以跟原来结点的值配对,也只能对答案贡献加 1。
时间复杂度 O(n log2 n)。
#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
	T x=0,w=1;char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*w;
}
template<class T> T read(T&x){
	return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;
co int N=50000+10;
vector<int> to[N],we[N];
int diameter;
int pretreat(int x,int fa){
	int maxd=0;
	for(int i=0;i<(int)to[x].size();++i){
		int y=to[x][i];
		if(y==fa) continue;
		int len=pretreat(y,x)+we[x][i];
		diameter=max(diameter,maxd+len);
		maxd=max(maxd,len);
	}
	return maxd;
}
int ans;
multiset<int> s[N];
typedef multiset<int>::iterator iter;
int dfs(int x,int fa,int k){
	s[x].clear();
	for(int i=0;i<(int)to[x].size();++i){
		int y=to[x][i];
		if(y==fa) continue;
		int val=dfs(y,x,k)+we[x][i];
		if(val>=k) ++ans;
		else s[x].insert(val);
	}
	int len=0;
	while(s[x].size()){
		if(s[x].size()==1) return max(len,*s[x].begin());
		iter i=s[x].lower_bound(k-*s[x].begin());
		if(i==s[x].begin() and s[x].count(*i)==1) ++i;
		if(i==s[x].end()){
			len=max(len,*s[x].begin());
			s[x].erase(s[x].begin());
		}
		else{
			++ans;
			s[x].erase(s[x].begin()),s[x].erase(s[x].find(*i)); // edit 1: find
		}
	}
	return len;
}
int check(int k){
	ans=0;
	dfs(1,0,k);
	return ans;
}
int main(){
//	freopen("testdata.in","r",stdin);
	int n=read<int>(),m=read<int>();
	for(int i=1;i<n;++i){
		int x=read<int>(),y=read<int>(),w=read<int>();
		to[x].push_back(y),we[x].push_back(w);
		to[y].push_back(x),we[y].push_back(w);
	}
	pretreat(1,0);
	int l=1,r=diameter;
	while(l<r){
//		cerr<<"l="<<l<<" r="<<r<<endl;
		int mid=(l+r+1)>>1;
		check(mid)>=m?l=mid:r=mid-1;
	}
	printf("%d\n",l);
	return 0;
}
NOIP2018 旅行 和 赛道修建的更多相关文章
- [NOIp2018提高组]赛道修建
		[NOIp2018提高组]赛道修建 题目大意: 给你一棵\(n(n\le5\times10^4)\)个结点的树,从中找出\(m\)个没有公共边的路径,使得第\(m\)长的路径最长.问第\(m\)长的路 ... 
- [NOIP2018 TG D1T3]赛道修建
		题目大意:$NOIP2018\;TG\;D1T3$ 题解:题目要求最短的赛道的长度最大,可以想达到二分答案,接着就是一个显然的树形$DP$. 发现对于一个点,它子树中若有两条链接起来比要求的答案大,一 ... 
- [NOIp2018] luogu P5021 赛道修建
		我同学的歌 题目描述 你有一棵树,每条边都有权值 did_idi.现在要修建 mmm 条赛道,一条赛道是一条连贯的链,且一条边至多出现在一条赛道里.一条赛道的长被定义为,组成这条赛道的边的权值之和. ... 
- Luogu5021 [NOIP2018]赛道修建
		Luogu5021 [NOIP2018]赛道修建 一棵大小为 \(n\) 的树,边带权.选 \(m\) 条链使得长度和最小的链最大. \(m<n\leq5\times10^4\) 贪心,二分答案 ... 
- 【LG5021】[NOIP2018]赛道修建
		[LG5021][NOIP2018]赛道修建 题面 洛谷 题解 NOIP之前做过增强版还没做出来\(QAQ\) 一看到题目中的最大值最小,就很容易想到二分答案 重点是考虑如何\(check\) 设\( ... 
- 竞赛题解 - NOIP2018 赛道修建
		\(\mathcal {NOIP2018}\) 赛道修建 - 竞赛题解 额--考试的时候大概猜到正解,但是时间不够了,不敢写,就写了骗分QwQ 现在把坑填好了~ 题目 (Copy from 洛谷) 题 ... 
- noip2018 D1T3 赛道修建
		题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 mm 条赛道. C 城一共有 nn 个路口,这些路口编号为 1,2,…,n1,2,…,n,有 n-1n−1 条适合于修建赛道的双向通 ... 
- 【noip2018】【luogu5021】赛道修建
		题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 mm 条赛道. C 城一共有 nn 个路口,这些路口编号为 1,2,…,n1,2,…,n,有 n-1n−1 条适合于修建赛道的双向通 ... 
- 题解 NOIP2018【赛道修建】—— 洛谷
		这道题有一点点树上dp的意思(大佬轻喷 我刚拿到这道题的时候毫无头绪,只知道这道题要二分答案 为什么是二分答案??? 题目: 目前赛道修建的方案尚未确定.你的任务是设计一 种赛道修建的方案,使得修建的 ... 
随机推荐
- mybatis异常集锦
			[Mybatis]报错:Malformed OGNL expression: name!= null and name != ' ' [Mybatis]报错:Malformed OGNL expres ... 
- 2019 CSP-J 游记(CQ LNBS考场 的退役之战)
			T0.10 爆零之战 已经不是第一次参加NOIP了(哦,关于兔子也NOIP了) 这次比赛的话,感觉考场很温馨,键盘很舒适,老师很友善,下次还会来.(哦不,下次来不了了,即将提前退役[大雾]) 刚刚文化 ... 
- find命令实例
			按时间查找也有参数 -atime 访问时间 -ctime 改变状态的时间 -mtime修改的时间. 这里的时间是以24小时为单位的. 查找最近30分钟修改的当前目录下的.php文件 find . -n ... 
- DatabaseGeneratedOption
			[DatabaseGenerated(DatabaseGeneratedOption.Identity)] 添加时 获取值 自增 默认值,,后期无法修改如:Id(AUTO_INCREMENT, ... 
- SGU 126. Boxes --- 模拟
			<传送门> 126. Boxes time limit per test: 0.25 sec. memory limit per test: 4096 KB There are two b ... 
- php数组到json的转变
			今天做项目遇到个问题,一个接口,输出二维数组,前端说他要的数据格式是数组,而不是对象,就像上个数据一样,我当时就懵逼了,,,什么对象?我明明输出的是数组啊...然后我看了看我返回的json串,emmm ... 
- DRF框架(六)——三大认证组件之认证组件、权限组件
			drf认证组件 用户信息表 from django.db import models from django.contrib.auth.models import AbstractUser class ... 
- 简单的爬虫程序以及使用PYQT进行界面设计(包含源码解析)
			由于这个是毕业设计的内容,而且还是跨专业的.爬虫程序肯定是很简单的,就是调用Yahoo的API进行爬取图片.这篇博客主要讲的是基础的界面设计. 放上源码,然后分部解析一下重要的地方.注:flickra ... 
- 【rt-thread】2、尝试用ENV添加18b20传感器
			尝试用ENV添加18b20传感器 rt-thread能通过env工具添加或者裁剪工程,这里调试的是通过ENV添加18b20传感器. 具体程序实现,可以参考以下资料 https://www.rt-thr ... 
- STM32 EV1527无线通信(433)
			EV1527无线通信 先说一下这个通信协议的数据格式,这个图片是我在手册里截的. 大家按照单片机类型计算周期,我的是STM32f103vb (4CLK大致等于350um) 发送时按照 先发同步码后发D ... 
