填很久以前的坑。

旅行

给一棵 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 ,其实这些值对答案有贡献就两种情况:

  1. val≥k
  2. 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 旅行 和 赛道修建的更多相关文章

  1. [NOIp2018提高组]赛道修建

    [NOIp2018提高组]赛道修建 题目大意: 给你一棵\(n(n\le5\times10^4)\)个结点的树,从中找出\(m\)个没有公共边的路径,使得第\(m\)长的路径最长.问第\(m\)长的路 ...

  2. [NOIP2018 TG D1T3]赛道修建

    题目大意:$NOIP2018\;TG\;D1T3$ 题解:题目要求最短的赛道的长度最大,可以想达到二分答案,接着就是一个显然的树形$DP$. 发现对于一个点,它子树中若有两条链接起来比要求的答案大,一 ...

  3. [NOIp2018] luogu P5021 赛道修建

    我同学的歌 题目描述 你有一棵树,每条边都有权值 did_idi​.现在要修建 mmm 条赛道,一条赛道是一条连贯的链,且一条边至多出现在一条赛道里.一条赛道的长被定义为,组成这条赛道的边的权值之和. ...

  4. Luogu5021 [NOIP2018]赛道修建

    Luogu5021 [NOIP2018]赛道修建 一棵大小为 \(n\) 的树,边带权.选 \(m\) 条链使得长度和最小的链最大. \(m<n\leq5\times10^4\) 贪心,二分答案 ...

  5. 【LG5021】[NOIP2018]赛道修建

    [LG5021][NOIP2018]赛道修建 题面 洛谷 题解 NOIP之前做过增强版还没做出来\(QAQ\) 一看到题目中的最大值最小,就很容易想到二分答案 重点是考虑如何\(check\) 设\( ...

  6. 竞赛题解 - NOIP2018 赛道修建

    \(\mathcal {NOIP2018}\) 赛道修建 - 竞赛题解 额--考试的时候大概猜到正解,但是时间不够了,不敢写,就写了骗分QwQ 现在把坑填好了~ 题目 (Copy from 洛谷) 题 ...

  7. noip2018 D1T3 赛道修建

    题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 mm 条赛道. C 城一共有 nn 个路口,这些路口编号为 1,2,…,n1,2,…,n,有 n-1n−1 条适合于修建赛道的双向通 ...

  8. 【noip2018】【luogu5021】赛道修建

    题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 mm 条赛道. C 城一共有 nn 个路口,这些路口编号为 1,2,…,n1,2,…,n,有 n-1n−1 条适合于修建赛道的双向通 ...

  9. 题解 NOIP2018【赛道修建】—— 洛谷

    这道题有一点点树上dp的意思(大佬轻喷 我刚拿到这道题的时候毫无头绪,只知道这道题要二分答案 为什么是二分答案??? 题目: 目前赛道修建的方案尚未确定.你的任务是设计一 种赛道修建的方案,使得修建的 ...

随机推荐

  1. P4Merge的使用

    (官网: https://www.perforce.com/products/helix-core-apps/merge-diff-tool-p4merge 可以作为一个stand alone app ...

  2. time 库

    time 库的三类函数 时间获取: >>> import time >>> time.time() 1570150181.4052463#单位为秒 >> ...

  3. 【转帖】Spark设计理念与基本架构

    Spark设计理念与基本架构 https://www.cnblogs.com/swordfall/p/9280006.html 1.基本概念 Spark中的一些概念: RDD(resillient d ...

  4. ACM算法锦集

    一:知识点 数据结构: 1,单,双链表及循环链表 2,树的表示与存储,二叉树(概念,遍历)二叉树的 应用(二叉排序树,判定树,博弈树,解答树等) 3,文件操作(从文本文件中读入数据并输出到文本文 件中 ...

  5. Python学习之路:通过分片的方式修改列表的技巧(拓展知识)

    一.为列表添加值 用分片的方式可以在列表的头部和尾部添加值 1.在列表的头部添加值 x = [1, 2, 3] #创建列表x x[:0] = [0] #用分片的方式在列表头部添加值 print(x) ...

  6. 【Python爬虫案例学习】分析Ajax请求并抓取今日头条街拍图片

    1.抓取索引页内容 利用requests请求目标站点,得到索引网页HTML代码,返回结果. from urllib.parse import urlencode from requests.excep ...

  7. day25——私有成员、类方法、静态方法、属性、isinstance和issubclass的区别

    day25 类的私有成员 当你遇到重要的数据,功能(只允许本类使用的一些方法,数据)设置成私有成员 python所有的私有成员都是纸老虎,形同虚设 类从加载时,只要遇到类中的私有成员,都会在私有成员前 ...

  8. Python之路【第十五篇】开发FTP多线程程序

    要求: 1.用户加密认证 2.允许同时多用户登录 3.每个用户有自己的家目录,且只能访问自己的家目录 4.对用户进行磁盘配额,每个用户的可用空间不同 5.允许用户在ftp server上随意切换目录 ...

  9. stone [期望]

    也许更好的阅读体验 \(\mathcal{Description}\) 有 \(n\) 堆石子,依次编号为 \(1, 2,\ldots , n\),其中第 \(i\) 堆有 \(a_i\) 颗石子 你 ...

  10. 向Spring 容器中注入对象的几种方法

    1.使用@Bean 注解,用于注入第三方 jar 包到SpringIOC容器中. 2.使用 @Import({Order.class, Member.class, MyImportBeanDefini ...