[CSP-S2019]树上的数 题解
CSP-S2 2019 D1T3
考场上写了2h还是爆零……思维题还是写不来啊
思路分析
最开始可以想到最简单的贪心,从小到大枚举每个数字将其移动到最小的节点。但是通过分析样例后可以发现,一个数字在移动的过程中也可能有无关的边的删除,很难处理。显然直接贪心是不可能的。
分析删边对图的影响。可以发现,一条边删去之后,边两端的部分将不会产生任何影响。也就是说,两边的关系只有这一条边。于是还是之前那个贪心的想法,将边的问题转化为点的问题。现在来分析怎么求解。
具体实现
分析样例后可以发现以下性质:
- 若某数字要从某个节点的某条边离开,那么这条边一定是这个节点最先被选择的边
- 某数字要从某个节点的x边进入,从y边离开,那么x一定先于y被选择,并且这个节点的其它边不在x和y之间被选择
- 某数字要最终停在某个节点,那么这个数字通往这个节点的边一定是这个节点最后被选择的边
因此,对于每个节点,关于与其相连的边,有以下三种约束条件:
- 某条边最先被选择
- 某条边紧跟着另一条边被选择
- 某条边最后被选择
我们可以根据上面提到的性质,通过判断每个节点的约束条件是否有冲突来求解方案。
可以发现,对于每个节点,其所有出边构成一条偏序链,我们可以通过维护一个链表来保证约束条件没有冲突。接下来分析一个数字经过一条边会产生什么冲突。假设某数字从$x$到$y$经过了边$(u,v)$。
1.若$x=u$,即$(u,v)$为路径的起始边,$u$为路径的起点
- $(u,v)$已经被其它数字沿相同方向走过,显然不能再走,不合法
- $u$上的原数字已走出去,显然不能再走,不合法
- 已经有数字搬运到$u$,即加上这条边后$u$的边将构成一条完整的偏序链,此时若有其它边不在这条偏序链上,因为要删去所有的边,不合法
2.若$v=y$,即$(u,v)$为路径的终边,$v$为路径的终点
- $(u,v)$已经被其它数字沿相同方向走过,显然不能再走,不合法
- $v$已有数字走入,显然不能再走,不合法
- 已经有数字从$v$搬运出去,即加上这条边后$v$的边将构成一条完整的偏序链,此时若有其它边不在这条偏序链上,因为要删去所有的边,不合法
3.若$x!=u$且$v!=y$,即$(u,v)$为路径的中间部分
- $(u,v)$已经被其它数字沿相同方向走过,显然不能再走,不合法
- 加上这条边后$v$的边将构成一条完整的偏序链,此时若有其它边不在这条偏序链上,因为要删去所有的边,不合法
- 加上这条边后构成的偏序链成为一个环,不合法
偏序链可以用链表O(1)维护。另外,可以发现,每次数字的转移要维护的是一些连续的节点的关系,因此可以用一遍dfsO(n)维护。加上枚举数字的O(n),总的时间复杂度O(n)。
细节比较多,注意不要漏点错点。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e3+100;
int T,n,tot;
int head[N],ver[2*N],Next[2*N];
int rev[N],pre[N],cnt1[N],cnt2[N],cnt3[N],from[N],to[N],p[N][N],header[N][N],tailer[N][N];
bool pd[N];
void add(int x,int y)
{
ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
ver[++tot]=x,Next[tot]=head[y],head[y]=tot;
}
void check(int x,int root)//root就是数字的起点
{
for(int i=head[x],y=ver[i];i;i=Next[i],y=ver[i])
if(y!=pre[x])
{
pre[y]=x,pd[y]=1;
if(x!=root)
{
if(p[x][y]==x || !p[x][y])
pd[y]=0;
if(tailer[x][y]==from[x] && header[x][pre[x]]==to[x] && cnt1[x]*2+cnt2[x]+cnt3[x]-2>0)
pd[y]=0;
if(tailer[x][y]==pre[x])
pd[y]=0;
}//中间边
else
{
if(p[x][y]==x || !p[x][y])
pd[y]=0;
if(from[x] && tailer[x][y]==from[x] && cnt1[x]*2+cnt2[x]+cnt3[x]-1>0)
pd[y]=0;
}//起始边
pd[y]&=pd[x];//x不行y也不行
check(y,root);
}
if(x==root)
pd[x]=0;//起终点相同也不行
else
if(from[x] ||(to[x] && tailer[x][to[x]]==pre[x] && cnt1[x]*2+cnt2[x]+cnt3[x]-1>0))
pd[x]=0;//x作为终点
}
void clear()
{
memset(head,0,sizeof(head));
memset(Next,0,sizeof(Next));
memset(from,0,sizeof(from));//该节点上的数字从哪条边进来
memset(to,0,sizeof(to));//该节点上的数字从哪条边出去
memset(cnt1,0,sizeof(cnt1));//该节点还剩下几条双向没走过的边
memset(cnt2,0,sizeof(cnt2));//该节点还剩下几条单向出边
memset(cnt3,0,sizeof(cnt3));//该节点还剩下几条双向出边
memset(pd,0,sizeof(pd));//可行性
memset(p,0,sizeof(p));//-1表示没走过,0表示双向都走过,x表示以x为起点单向走过这条边,这里的初始化好像没什么用
memset(header,0,sizeof(header));//偏序链起始边
memset(tailer,0,sizeof(tailer));//偏序链终边
tot=0;
}
int main()
{
scanf("%d",&T);
while(T--)
{
clear();
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&rev[i]);
for(int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
cnt1[x]++,cnt1[y]++;
p[x][y]=p[y][x]=-1;
header[x][y]=tailer[x][y]=y,header[y][x]=tailer[y][x]=x;//初始值
}
for(int i=1,now;i<=n;i++)
{
for(int j=1;j<=n;j++)
pre[j]=0;
pd[rev[i]]=1;//初始值
check(rev[i],rev[i]);//dfs判断可行性
for(int j=1;j<=n;j++)
if(pd[j])
{
now=j;
break;
}//找到字典序最小的可行终点
printf("%d ",now);
from[now]=pre[now];
while(pre[now]!=rev[i])
{
if(p[pre[now]][now]==-1)
{
p[pre[now]][now]=p[now][pre[now]]=pre[now];
cnt1[now]--,cnt1[pre[now]]--,cnt3[now]++,cnt2[pre[now]]++;
}//双向没走过
else
{
p[pre[now]][now]=p[now][pre[now]]=0;
cnt2[now]--,cnt3[pre[now]]--;
}//反向走过
header[pre[now]][tailer[pre[now]][now]]=header[pre[now]][pre[pre[now]]];
tailer[pre[now]][header[pre[now]][pre[pre[now]]]]=tailer[pre[now]][now];//链表插入
now=pre[now];
}
if(p[pre[now]][now]==-1)
{
p[pre[now]][now]=p[now][pre[now]]=pre[now];
cnt1[now]--,cnt1[rev[i]]--,cnt3[now]++,cnt2[rev[i]]++;
}
else
{
p[pre[now]][now]=p[now][pre[now]]=0;
cnt2[now]--,cnt3[rev[i]]--;
}
to[rev[i]]=now;
}
puts("");
}
}
[CSP-S2019]树上的数 题解的更多相关文章
- CSP2019 树上的数 题解
题面 这是一道典型的部分分启发正解的题. 所以我们先来看两个部分分. Part 1 菊花图 这应该是除了暴力以外最好想的一档部分分了. 如上图(节点上的数字已省略),如果我们依次删去边(2)(1)(3 ...
- [CSP day1T3]树上的数
题面 题解 这道题由于是求字典序最小的,所以要贪心地枚举数字,然后找可以走到的编号最小的点,处理这条路径. 这条路径有一些特性. 以下是特别精炼的结论: 所以一旦选好了路径,这些边的先后顺序就被定死了 ...
- CCF CSP 201312-4 有趣的数
CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201312-4 有趣的数 问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0 ...
- 【CSP2019】树上的数
[CSP2019]树上的数 题面 洛谷 题解 我们设每个点上的编号分别为\(a_1,a_2...a_n\). 10pts ... 菊花 假设现在菊花中心编号是\(rt\),设你依次拆边\((p_1,r ...
- C#版 - Leetcode 504. 七进制数 - 题解
C#版 - Leetcode 504. 七进制数 - 题解 Leetcode 504. Base 7 在线提交: https://leetcode.com/problems/base-7/ 题目描述 ...
- C#版 - Leetcode 306. 累加数 - 题解
版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C#版 - L ...
- C#版(打败97.89%的提交) - Leetcode 202. 快乐数 - 题解
版权声明: 本文为博主Bravo Yeung(知乎UserName同名)的原创文章,欲转载请先私信获博主允许,转载时请附上网址 http://blog.csdn.net/lzuacm. C#版 - L ...
- BZOJ3930:[CQOI2015]选数——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=3930 https://www.luogu.org/problemnew/show/P3172#sub ...
- 洛谷P1037 产生数 题解 搜索
题目链接:https://www.luogu.com.cn/problem/P1037 题目描述 给出一个整数 \(n(n<10^{30})\) 和 \(k\) 个变换规则 \((k \le 1 ...
随机推荐
- ASP.NET Core 监听SQL Server数据库的实时信息
1.开发环境: 开发工具:Visual Studio 2019 数据库:SQL Server2012 开发环境:.Net Core 3.1 2.使用技术: Signalr:实现消息推送 SqlDepe ...
- PHP - AJAX 与 MySQL-AJAX 数据库实例
PHP - AJAX 与 MySQL AJAX 可用来与数据库进行交互式通信. AJAX 数据库实例 下面的实例将演示网页如何通过 AJAX 从数据库读取信息: 本教程使用到的 Websites 表 ...
- PHP xml_get_error_code() 函数
定义和用法 xml_get_error_code() 函数获取 XML 解析器错误代码.高佣联盟 www.cgewang.com 如果成功,该函数则返回错误代码.如果失败,则返回 FALSE. 语法 ...
- PHP children() 函数
实例 查找 note 节点的子节点: <?php$note=<<<XML<note><to>Tove</to>高佣联盟 www.cgewan ...
- ElasticSearch 基础入门 and 操作索引 and 操作文档
基本概念 索引: 类似于MySQL的表.索引的结构为全文搜索作准备,不存储原始的数据. 索引可以做分布式.每一个索引有一个或者多个分片 shard.每一个分片可以有多个副本 replica. 文档: ...
- luogu 4331 [BalticOI 2004]Sequence 数字序列
LINK:数字序列 这是一道论文题 我去看了一眼论文鸽的论文. 发现讲的还算能懂.可并堆的操作也讲的比较清晰. 对于这道题首先有一个小trick 我们给a数组全部减去其对应的下标这样我们求出来的b数组 ...
- this.getClass().getResource(String) 路径问题
this.getClass().getResource(String) 路径问题 这里的默认当前路径是该类所在目录: this.getClass() 说明了一切!! 找到类,就找文件:很显然和类 ...
- Paper English
论文中的英语 单词 a arange 整理 ambiguity 含糊的 aggregate 总量 auxiliary 辅助的 alleviate 缓解 aberrant 异常的 akin 类似的 Ac ...
- 基于OpenSIPS做注册服务下,场景A打B,一方发起BYE挂断后收到500,另一方无法挂断的问题
基于OpenSIPS做注册服务下,场景A打B,一方发起BYE挂断后收到500,另一方无法挂断的问题 最近在工作中遇到一个看似很奇怪的,排除起来很费劲,但最后的解决方式又及其简单的问题,下面我们 ...
- ALGEBRA-2 有限维向量空间
关键词:张成.线性无关.基.维度 linear span: V中任意一组向量的span都是V的子空间(对加法和数乘封闭) linear independent 线性无关 https://www.zy ...