题面

题解

这道题由于是求字典序最小的,所以要贪心地枚举数字,然后找可以走到的编号最小的点,处理这条路径。

这条路径有一些特性。

以下是特别精炼的结论:

所以一旦选好了路径,这些边的先后顺序就被定死了,后面的路径肯定不能与他冲突

于是我们只要记录边的先后关系,然后进行非常严密的逻辑判断选择一条不冲突的路径。

复杂度O(n^2)

Code

你们看不懂的

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#define LL long long
using namespace std;
int read() {
int f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s == '-')f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
return x * f;
}
struct ed{
int v,id;
ed(){}
ed(int V,int I){v = V;id = I;}
};
vector<ed> g[2005];
int id[2005];
int pre[8005],suf[8005];
int fa[8005];
int le[8005];
int minn;
int find(int x) {
if(fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}
void unionSet(int a,int b) {
int u = find(a),v = find(b);
if(u < v) le[u] += le[v],fa[v] = u;
else le[v] += le[u],fa[u] = v;
}
int n,m,i,j,s,o,k;
void dfs(int x,int fat,int fai) {
if(fai != 0 && (((find(fai) > n || le[find(fai)] == g[x].size()) && !suf[fai] && !pre[x + n]) || g[x].size() == 1)) minn = min(minn,x);
// printf("minn:%d x:%d find[%d]:%d\n",minn,x,fai,find(fai));
for(int i = 0;i < g[x].size();i ++) {
int y = g[x][i].v,z = g[x][i].id;
if((fai == 0 && (((find(z) > 2*n || le[find(z)] == g[x].size()) && !pre[z] && !suf[x]) || g[x].size() == 1)) || (y != fat && !pre[z] && !suf[fai] && find(fai) != find(z) && !(find(fai) <= n && find(z) <= 2*n && le[find(fai)] + le[find(z)] != g[x].size()))) {
int zi = z;
if(zi <= 3 * n) zi += n;
else zi -= n;
dfs(g[x][i].v,x,zi);
}
}
return ;
}
bool dfs2(int x,int fat,int mini,int fai) {
if(x == mini) {
suf[fai] = x + n;
pre[x + n] = fai;
unionSet(x + n,fai);
return 1;
}
bool ff = 0;
for(int i = 0;i < g[x].size();i ++) {
if(g[x][i].v != fat) {
int z = g[x][i].id,zi = g[x][i].id;
if(z <= 3*n) z += n;
else z -= n;
bool fff = ff;
ff |= dfs2(g[x][i].v,x,mini,z);
if(!fff && ff) {
if(fai == 0) {
pre[zi] = x;
suf[x] = zi;
unionSet(x,zi);
}
else {
pre[zi] = fai;
suf[fai] = zi;
unionSet(fai,zi);
}
}
}
}
return ff;
}
int main() {
// freopen("tree.in","r",stdin);
// freopen("tree.out","w",stdout);
int T;
scanf("%d",&T);
while(T --) {
scanf("%d",&n);
memset(pre,0,sizeof(pre));
memset(suf,0,sizeof(suf));
memset(le,0,sizeof(le));
for(int i = 1;i < n;i ++) {
id[i] = read();
g[i].clear();
fa[i] = i;
fa[i + n] = i + n;
fa[i + 2*n] = i + n*2;
fa[i + 3*n] = i + n*3;
}
scanf("%d",&id[n]);
g[n].clear();
fa[n] = n;
fa[2*n] = 2*n;
fa[3*n] = 3*n;
fa[4*n] = 4*n;
for(int i = 1;i < n;i ++) {
s = read();o = read();
g[s].push_back(ed(o,i + n*2));
g[o].push_back(ed(s,i + n*3));
le[i + n*2] = le[i + n * 3] = 1;
}
// for(int i = 1;i <= n;i ++) printf("p:%d size:%d\n",i,g[i].size());
for(int i = 1;i <= n;i ++) {
s = id[i];
minn = 0x7f7f7f7f;
// cout<<"point:"<<i<<"("<<s<<")"<<endl;
dfs(s,0,0);
if(minn <= n) {
id[i] = minn;
dfs2(s,0,minn,0);
}
}
for(int i = 1;i <= n;i ++) {
printf("%d ",id[i]);
}putchar('\n');
}
return 0;
}

[CSP day1T3]树上的数的更多相关文章

  1. CCF CSP 201312-4 有趣的数

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201312-4 有趣的数 问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0 ...

  2. 【CSP2019】树上的数

    [CSP2019]树上的数 题面 洛谷 题解 我们设每个点上的编号分别为\(a_1,a_2...a_n\). 10pts ... 菊花 假设现在菊花中心编号是\(rt\),设你依次拆边\((p_1,r ...

  3. CSP2019 树上的数 题解

    题面 这是一道典型的部分分启发正解的题. 所以我们先来看两个部分分. Part 1 菊花图 这应该是除了暴力以外最好想的一档部分分了. 如上图(节点上的数字已省略),如果我们依次删去边(2)(1)(3 ...

  4. CSP2019 D1T3 树上的数 (贪心+并查集)

    题解 因为博主退役了,所以题解咕掉了.先放个代码 CODE #include<bits/stdc++.h> using namespace std; const int MAXN = 20 ...

  5. [CSP-S2019]树上的数 题解

    CSP-S2 2019 D1T3 考场上写了2h还是爆零……思维题还是写不来啊 思路分析 最开始可以想到最简单的贪心,从小到大枚举每个数字将其移动到最小的节点.但是通过分析样例后可以发现,一个数字在移 ...

  6. [CSP-S2019] 树上的数

    考虑处理字典序的一类经典操作: 按位枚举. 我们思考一些性质: 一个点的权值出去则不会再回来. 一条边不会使用两次. 那么我们从小到大来操作. 那么存在矛盾当且仅当: 起点在之前非开始边被操作过 中间 ...

  7. 【CSP2019】题解合集

    诈个尸 先挖坑 虽然连去都没去但还是想做做 今年貌似比去年还毒瘤啊... yrx.hjw都进了省队线tql orz (myh:没AK真丢脸 Day1T1 格雷码 Day1T2 括号树 Day1T3 树 ...

  8. CSP-S 2019 Solution

    Day1-T1 格雷码(code) 格雷码是一种特殊的 \(n\) 位二进制串排列法,要求相邻的两个二进制串恰好有一位不同,环状相邻. 生成方法: \(1\) 位格雷码由两个 \(1\) 位的二进制串 ...

  9. CSP-S乱搞记

    还有一年的时间,没人能挡住我前进的脚步 以后不打算写游记了,补完这篇再写就等退役吧,不太想传播什么负能量,走这条路,希望能得到自己想要的东西 Day-n 上了一个月文化课,班主任突然催我搞竞赛??? ...

随机推荐

  1. C#和Java,究竟选哪个方向?我只说事实,你自己分析……

    好久没到园子里面逛了,回来看了看,.NET有点式微呀?Java/Spring/Linux--比以前多了很多,为什么?博客园可是.NET的大本营了呀! 好吧,我承认,飞哥也动摇了,去年在ASP.NET的 ...

  2. Apache Shiro反序列化漏洞(Shiro550)

    1.漏洞原理: Shiro 是 Java 的一个安全框架,执行身份验证.授权.密码.会话管理 shiro默认使用了CookieRememberMeManager,其处理cookie的流程是:得到rem ...

  3. 在Visual Studio 2019中使用scanf报错C4996解决办法

    错误警告信息 错误C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To ...

  4. 百度地图API 地图圈区域并计算坐标点是否在区域内

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 机械硬盘和ssd固态硬盘的原理对比分析

    固态硬盘和机械硬盘的区别 机械硬盘 磁头是不是直接和盘片接触的呢 磁盘中有几个盘片 机械硬盘的工作原理 固态硬盘的寻址方式 SMR叠瓦式真的比PMR优秀吗 固态硬盘 主控芯片 闪存颗粒 缓存单元 固态 ...

  6. Python快速下载商品数据,并连接数据库,保存数据

    开发环境 python 3.8 pycharm 2021.2 专业版 代码实现 发送请求 获取数据 解析数据(筛选数据) 保存数据 连接数据库 开始代码 请求数据 # 伪装 headers = { ' ...

  7. 本地拉取服务器上的项目,SVN 由于目标计算机积极拒绝 无法连接失败

    下面几种解决方案一定一定一定都要试一下哈, 比如,如果你的SVN没有启动,并且防火墙也开启了,那么你即便启动了SVN,也是无法拉取项目的,需要把防火墙也关闭. 1.是否启动了svn 输入命令查看是否启 ...

  8. Day01 对前端的初步了解

    了解了工作性质以及流程 产品经理+UI+前端程序员+后端程序员+测试人员 了解了工作会做到的项目 pc端项目,后台管理系统,APP,小程序,移动端网页 了解了后续需要学到的课程 HTML+CSS Ja ...

  9. CF1656E Equal Tree Sums 题解

    题目链接 思路分析 自认为是一道很好的构造题,但是我并不会做. 看了题解后有一些理解,在这里再梳理一遍巧妙的思路. 我们先来看这样的一张图: 我们发现当去掉叶子节点的父亲时,剩下树的价值和等于叶子节点 ...

  10. Tapdata 数据库实时同步的技术要点

    Tapdata 是由深圳钛铂数据有限公司研发的一款实时数据处理及服务的平台产品,企业可以使用 Tapdata 快速构建数据中台和实时数仓, Tapdata 提供了一站式的解决方案,包括实时数据采集.数 ...