Luogu P3549 [POI 2013] MUL-Multidrink 题解
P3549 [POI 2013] MUL-Multidrink
非常 tricky 的一道题,模拟赛拼尽全力无法战胜,写篇题解记录一下。
容易理解的直接构造法。
按原题限制随便跳会破坏很多性质,几乎无法定向构造。考虑最后必须到 \(n\),每经过一个点,必须要遍历其所有子树,而从 \(1\to n\) 至少会经过之间的路径,路径上的节点可以调整为依次经过,所以考虑把 \(1\to n\) 的路径提出来,每次考虑子树内的构造,走完之后再走到路径上下一个节点。
考虑一个点的子树走到下一个点的子树,只会从这个点子树的根或一个儿子走到另一个点子树的根或一个儿子。
考虑从一个点的子树走出来,结合决策包容性,发现能从根节点节点走出来就从根节点走,否则就从根节点的儿子走出来。发现此时已经不存在决策了,对每个点记录能否到自己和自己儿子,按照优先级决策,可以直接构造。
观察每一次的操作,我们发现就是要实现对于每个节点的子树儿子进自己出或自己进儿子出的构造。考虑把这些组合成一个操作。
考虑无解的情况,以某个节点自己进儿子出为例。如果存在两棵大小大于 \(1\) 的子树,进入其中一棵子树回来的时候这个节点和对应子树的子节点都已经被访问过,无解。且在任意情况下,无论怎么遍历,无解的依旧无解。
以某个节点自己进儿子出为例。由上述分析有解时每个点只会有一个大小大于 \(1\) 的子树,大小为 \(1\) 的子树可以在儿子进自己出地访问完这棵子树后顺次访问,自己进儿子出访问显然无解。于是归约为了更小的问题,递归构造。时间复杂度 \(O(n)\)。
#include <bits/stdc++.h>
using namespace std;
struct edge
{
int v,nxt;
}e[4000001];
int n,u,v,h[2000001],fa[2000001],siz[2000001],ans[2000001],st[2000001],tol=0,mx=0,cnt=0,top=0;
bool vis[2000001];
void cstr_sf(int,int);
void cstr_fs(int,int);
void add_edge(int u,int v)
{
e[++cnt].nxt=h[u];
e[cnt].v=v;
h[u]=cnt;
}
void end()
{
printf("BRAK\n");
exit(0);
}
void cstr_sf(int x,int pr)
{
vector<int>ss,sl;
for(int i=h[x];i;i=e[i].nxt)
if(e[i].v!=pr&&!vis[e[i].v]&&siz[e[i].v]==1)ss.push_back(e[i].v);
else if(e[i].v!=pr&&!vis[e[i].v])sl.push_back(e[i].v);
if(sl.size()>=2)end();
for(int i=0;i<ss.size();i++)ans[++tol]=ss[i];
for(int i=0;i<sl.size();i++)cstr_fs(sl[i],x);
ans[++tol]=x;
}
void cstr_fs(int x,int pr)
{
ans[++tol]=x;
vector<int>ss,sl;
for(int i=h[x];i;i=e[i].nxt)
if(e[i].v!=pr&&!vis[e[i].v]&&siz[e[i].v]==1)ss.push_back(e[i].v);
else if(e[i].v!=pr&&!vis[e[i].v])sl.push_back(e[i].v);
if(sl.size()>=2)end();
for(int i=0;i<sl.size();i++)cstr_sf(sl[i],x);
for(int i=0;i<ss.size();i++)ans[++tol]=ss[i];
}
void dfs(int x,int pr)
{
siz[x]=1,fa[x]=pr;
for(int i=h[x];i;i=e[i].nxt)
if(e[i].v!=pr)dfs(e[i].v,x),siz[x]+=siz[e[i].v];
}
bool cstr(int x,int pr,bool flag)
{
vector<int>ss,sl;
for(int i=h[x];i;i=e[i].nxt)
if(e[i].v!=pr&&!vis[e[i].v]&&siz[e[i].v]==1)ss.push_back(e[i].v);
else if(e[i].v!=pr&&!vis[e[i].v])sl.push_back(e[i].v);
if(x==n)
{
if(siz[x]==1)ans[++tol]=x;
else
{
if(!flag)end();
cstr_sf(x,pr);
}
return 0;
}
bool tf=0;
if(ss.empty()&&sl.empty())ans[++tol]=x,tf=1;
else if(!flag)
{
if(sl.size()>=2)end();
ans[++tol]=x,tf=0;
for(int i=0;i<sl.size();i++)cstr_sf(sl[i],x);
for(int i=0;i<ss.size();i++)ans[++tol]=ss[i];
}
else
{
if(sl.size()==0)
{
for(int i=0;i<ss.size();i++)ans[++tol]=ss[i];
ans[++tol]=x,tf=1;
}
else if(sl.size()==1)
{
for(int i=0;i<ss.size();i++)ans[++tol]=ss[i];
for(int i=0;i<sl.size();i++)cstr_fs(sl[i],x);
ans[++tol]=x,tf=1;
}
else if(sl.size()==2)
{
cstr_fs(sl[0],x),ans[++tol]=x,tf=0,cstr_sf(sl[1],x);
for(int i=0;i<ss.size();i++)ans[++tol]=ss[i];
}
else end();
}
return tf;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++)scanf("%d%d",&u,&v),add_edge(u,v),add_edge(v,u);
dfs(1,0);
int x=n;
while(x)vis[x]=1,st[++top]=x,x=fa[x];
bool tf=0;
for(int i=top;i>=1;i--)tf=cstr(st[i],0,tf);
for(int i=1;i<=tol;i++)printf("%d\n",ans[i]);
return 0;
}
Luogu P3549 [POI 2013] MUL-Multidrink 题解的更多相关文章
- Luogu 1979 NOIP 2013 华容道(搜索,最短路径)
Luogu 1979 NOIP 2013 华容道(搜索,最短路径) Description 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面 ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
- Moscow Subregional 2013. 部分题题解 (6/12)
Moscow Subregional 2013. 比赛连接 http://opentrains.snarknews.info/~ejudge/team.cgi?contest_id=006570 总叙 ...
- luogu NOIp热身赛(2018-11-07)题解
为什么前面的人都跑得那么快啊? QAQ T1:区间方差 题目大意:询问区间方差,支持单点修改 首先把方差的式子展开,得到 $$d = \frac{a_1 + ... a_n}{n} - \frac{a ...
- 【luogu P1955 [NOI2015]程序自动分析】 题解
题目链接:https://www.luogu.org/problemnew/show/P1955 并查集操作,1e9要离散化,数组要开大一些,操作前先执行合并操作 样例好毒啊(全是排好序的) #inc ...
- 【luogu P2195 HXY造公园】 题解
题目链接:https://www.luogu.org/problemnew/show/P2195 fir.吐槽题目(省略1w字 sec.考虑对一个森林的维护,每棵树用并查集维护. 操作1:输出当前查询 ...
- 【luogu P1073 最优贸易】 题解
题目链接:https://www.luogu.org/problemnew/show/P1073 对于状态量相互影响的题目,分层图是个不错的想法. 考虑在题目中分为: 不交易: 直接从1到n出去,为0 ...
- 【luogu P3393 逃离僵尸岛】 题解
题目链接:https://www.luogu.org/problemnew/show/P3393 被占领的点可以先连在一个点上然后只需要对这一个点bfs一遍就可以求所有的危险点 #include &l ...
- 【luogu P4017 最大食物链计数】 题解
题目链接:https://www.luogu.org/problemnew/show/P4017 DAG + DP #include <queue> #include <cstdio ...
- 【luogu P1351 联合权值】 题解
题目链接:https://www.luogu.org/problemnew/show/P1351 做了些提高组的题,不得不说虽然NOIP考察的知识点虽然基本上都学过,但是做起题来还是需要动脑子的. 题 ...
随机推荐
- 详细介绍Java的SPI机制
一.什么是SPI机制 SPI(Service Provider Interface),是JDK内置的一种 服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如java.s ...
- VScode设置用户代码片段快捷方式
一.创建步骤 a. b. 二.创建模板 { "生成vue模板": { "prefix": "vue", "body": ...
- json导出csv
let data = [] let keys = ['name', 'town', 'village', 'address', 'update_time_label', 'manager'] let ...
- DP学习总结
动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法. -----OI Wiki 例.1-最大子段和 分析 DP四步 ⑴定义状态 定义\(dp_i\)表示以\(i\)结尾的最大子段 ...
- 鸿蒙原生开源库 ViewPool 在 OpenHarmony 社区正式上线
近日,由伙伴参与共建的鸿蒙原生开源库"ViewPool"在OpenHarmony社区正式上线.这个开发库是基于OpenHarmony技术孵化的成果,充分发挥了平台的技术特性,同时融 ...
- IP到国家代码映射之GeoLite2导入到MySQL形成数据字典
一.准备CSV文件与MySQL表结构 下载并解压GeoLite2-Country-CSV数据 从 MaxMind 下载 GeoLite2-Country-CSV.zip,解压后获取以下文件: G ...
- K8s新手系列之DaemonSet资源
概述 官网文档:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/daemonset/ DaemonSet简称ds Dae ...
- 乌班图源码编译安装nginx
第一步:下载 wget http://nginx.org/download/nginx-1.16.0.tar.gz 第二步:解压 tar -xzf Nginx-1.16.0.tar.gz 第三步:编译 ...
- 邮件收件、读取邮件API-批量导入-支持代理-开放HTTP接口
简介 大恩邮箱收件平台,支持读取收件箱.垃圾箱的邮件.支持批量导入各大邮箱平台的账号(例如微软.谷歌.网易.QQ等),采用pop3.imap协议收件,支持配置代理IP.验证码截取规则等,同时提供了HT ...
- 洛谷 P3201 [HNOI2009] 梦幻布丁
洛谷 P3201 [HNOI2009] 梦幻布丁 祭我AC的第十道紫题. 听了一下午的 才调出来. 题意分析 洛谷传送门 给一个序列a,有两种操作-- 1 x y将序列中所有x全部变成y 2查询当前序 ...