@codeforces - 1214H@ Tiles Placement
@description@
给定一个 n 点的树,一条简单路径的长度为这条路径所含点的个数。
现给每个点涂色,颜色编号为 1~k。要求每一条长度恰为 k 的简单路径上点的颜色互不相同。
请构造一个方案,或者判定无解。
Input
第一行两个整数 n,k (2≤k≤n≤200000),表示点的个数与颜色个数。
接下来 n-1 行,每行两个整数 vi 和 ui (1≤vi,ui≤n),描述了每条边。
保证是一棵树。
Output
如果无解输出 "No"。
否则输出 "Yes",接下来输出 n 个数表示每个点的颜色。
Examples
Input
7 4
1 3
2 3
3 4
4 5
5 6
5 7
Output
Yes
1 1 2 3 4 1 1
Input
7 3
1 3
2 3
3 4
4 5
5 6
5 7
Output
No
Note
第一个样例方案如下:

@solution@
@part - 1@
首先看一种特殊情况:一条链。
显然我们可以从链的前面往后依次涂 1, 2, ..., k, 1, 2, ...,这个方案是一定合法的。
并且可以注意到,其他方案总可以等价地转成这个方案(相同的颜色依然相同)。
再来看一种特殊情况:k = 2。
实际上就是二分图染色,不难发现这个情况也是一定合法。
如果无解,至少要满足 k > 2,且有一个点是三叉的。

如图,a, b, c 是三条不相交的链。
如果满足 a + b >= k,b + c >= k,c + a >= k 则无解(这里的长度为点的数量)。
至于怎么证,不妨假设 a >= b >= c,则一定有 a >= k/2。
则一定可以 a 选出长度 p,b 选出长度 q,c 选出长度 r 使得 p + q = p + r = k,且 p >= k/2;q, r < k/2。
又因为 b + c >=k,所以 q 段与 r 段一定可以在同一个长度为 k 的段里面。又因为 q, r 的颜色集合相同,于是矛盾。
注意要特判 k = 2,这个证明对 k = 2 不成立。
其实当 a >= b >= c 时,只需要保证 b + c >= k 就肯定无解了。
@part - 2@
然后开始我们的构造。
首先取出这棵树的直径,按照链的方法给这个直径涂色。
因为直径的性质,所有点一定距离直径的某一个端点最远,因此我们只需要找出次远和第三远就可以判断无解了。
从直径的某个端点开始 dfs。对于直径外的点,父亲的那条边连向直径,次远和第三远一定在它的子树中产生。
而对于直径上的点,次远和第三远还可能连向直径的另一个端点,需要另行判断。
假如以上无解判断完成后,我们以直径的中间边为界,开始往两边 dfs,相同深度的涂相同颜色。
然后就构造完成了。没错,这样一定是一个合法的方案。
可以反证,假如存在一个不合法的路径。考虑以下三种可能的位置情况:
(1)与直径不相交:

这种情况上面早就判掉了。
(2)与直径有交,但不经过直径中心边:

根据直径的定义,红色肯定没有绿色长,而假如绿色长度 >= k 上面也已经判掉了。
(3)与直径有交且直径中心边:

这个时候的确有可能长度 >= k,但是按照上面的构造方法,这种情况一定不会出现相同的颜色。
@accepted code@
#include<cstdio>
#include<cstdlib>
const int MAXN = 200000;
struct edge{
int to; edge *nxt;
}edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt = &edges[0];
int clr[MAXN + 5], n, k;
void addedge(int u, int v) {
edge *p = (++ecnt);
p->to = v, p->nxt = adj[u], adj[u] = p;
p = (++ecnt);
p->to = u, p->nxt = adj[v], adj[v] = p;
}
int dep[MAXN + 5];
void dfs1(int x, int f) {
dep[x] = dep[f] + 1;
for(edge *p=adj[x];p;p=p->nxt)
if( p->to != f ) dfs1(p->to, x);
}
int get_pos(int x) {
dfs1(x, 0); int mx = x;
for(int i=1;i<=n;i++)
if( dep[i] > dep[mx] ) mx = i;
return mx;
}
bool tag[MAXN + 5];
void dfs2(int x, int f) {
for(edge *p=adj[x];p;p=p->nxt)
if( p->to != f ) {
dfs2(p->to, x);
tag[x] |= tag[p->to];
}
}
int f[MAXN + 5], g[MAXN + 5];
int nxt(int x) {return (x == k) ? 1 : x + 1;}
int lst(int x) {return (x == 1) ? k : x - 1;}
void dfs4(int x, int fa, int type) {
if( type ) clr[x] = nxt(clr[fa]);
else clr[x] = lst(clr[fa]);
for(edge *p=adj[x];p;p=p->nxt)
if( p->to != fa ) {
dfs4(p->to, x, type);
if( f[p->to] + 1 > f[x] )
g[x] = f[x], f[x] = f[p->to] + 1;
else if( f[p->to] + 1 > g[x] )
g[x] = f[p->to] + 1;
}
if( f[x] && g[x] && f[x] + g[x] + 1 >= k ) {
puts("No");
exit(0);
}
}
int mxdep;
void dfs3(int x, int fa) {
clr[x] = nxt(clr[fa]); f[x] = g[x] = 0;
for(edge *p=adj[x];p;p=p->nxt)
if( p->to != fa ) {
if( tag[p->to] ) dfs3(p->to, x);
else {
if( dep[x] <= mxdep - dep[x] + 1 )
dfs4(p->to, x, 0);
else dfs4(p->to, x, 1);
if( f[p->to] + 1 > f[x] )
g[x] = f[x], f[x] = f[p->to] + 1;
else if( f[p->to] + 1 > g[x] )
g[x] = f[p->to] + 1;
}
}
if( f[x] && g[x] && f[x] + g[x] + 1 >= k ) {
puts("No");
exit(0);
}
if( f[x] && f[x] + dep[x] >= k && f[x] + mxdep - dep[x] + 1 >= k ) {
puts("No");
exit(0);
}
}
int main() {
scanf("%d%d", &n, &k);
for(int i=1;i<n;i++) {
int u, v; scanf("%d%d", &u, &v);
addedge(u, v);
}
if( k == 2 ) {
puts("Yes"), get_pos(1);
for(int i=1;i<=n;i++)
printf("%d ", (dep[i] & 1) + 1);
return 0;
}
int p = get_pos(1), q = get_pos(p); mxdep = dep[q];
tag[q] = true, dfs2(p, 0), clr[0] = k, dfs3(p, 0);
puts("Yes");
for(int i=1;i<=n;i++)
printf("%d ", clr[i]);
puts("");
}
@details@
因为没特判 k = 2,狠狠地 WA 了一发。
@codeforces - 1214H@ Tiles Placement的更多相关文章
- Codeforces 1500D - Tiles for Bathroom(贪心+队列)
Codeforces 题面传送门 & 洛谷题面传送门 首先先讲一发我的 \(n^2q\log n\) 的做法,虽然没有付诸实现并且我也深知它常数巨大过不去,但是我还是决定讲一讲(大雾 考虑设 ...
- Codeforces 1178C. Tiles
传送门 考虑一块块填,首先 $(1,1)$ 有 $4$ 种方案 然后根据 $(1,1)$ 的右边颜色,$(1,2)$ 有两种方案,$(1,3)$ 根据 $(1,2)$ 也有两种方案... 考虑 $(2 ...
- world.construct(me);
目录 0 引言 0.1 所谓构造题 0.2 重点是动机 (motivation) 1 实践出真知 1.1 「CSP-S 2021」「洛谷 P7915」回文 1.1.1 题目大意 1.1.2 解题过程 ...
- Codeforces Round #292 (Div. 1) B. Drazil and Tiles 拓扑排序
B. Drazil and Tiles 题目连接: http://codeforces.com/contest/516/problem/B Description Drazil created a f ...
- CodeForces - 516B Drazil and Tiles(bfs)
https://vjudge.net/problem/CodeForces-516B 题意 在一个n*m图中放1*2或者2*1的长方形,问是否存在唯一的方法填满图中的‘.’ 分析 如果要有唯一的方案, ...
- Codeforces Round #292 (Div. 1) B. Drazil and Tiles (类似拓扑)
题目链接:http://codeforces.com/problemset/problem/516/B 一个n*m的方格,'*'不能填.给你很多个1*2的尖括号,问你是否能用唯一填法填满方格. 类似t ...
- Codeforces Round #292 (Div. 1) - B. Drazil and Tiles
B. Drazil and Tiles Drazil created a following problem about putting 1 × 2 tiles into an n × m gri ...
- 【codeforces 516B】Drazil and Tiles
题目链接: http://codeforces.com/problemset/problem/516/B 题解: 首先可以得到一个以‘.’为点的无向图,当存在一个点没有边时,无解.然后如果这个图边双联 ...
- CodeForces 516B Drazil and Tiles 其他
原文链接http://www.cnblogs.com/zhouzhendong/p/8990658.html 题目传送门 - CodeForces 516B 题意 给出一个$n\times m$的矩形 ...
随机推荐
- react前端自动化webpack配置
1. npm init2. package.json install dependence webpack webpack-dev-server react react-dom react-hot-l ...
- HTML 语法简要总结
HTML基本语法 认识网页 网页主要由文字.图像和超链接等元素构成.当然,除了这些元素,网页中还可以包含音频.视频以及Flash等. 常见浏览器内核介绍 浏览器是网页运行的平台,常用的浏览器有IE.火 ...
- Constructing Roads POJ - 2421 (最小生成树)
思路:首先使用二维数组dis[][]处理输入, 对于已经修好的路,将其对应的dis[i][j]置为零即可.最后再将 所有的dis[][]保存到边结构体中,使用Kruskal算法求得最小生成树. ...
- jsp页面_按回车键触发事件
一般在列表页面中,都会带有查询按钮,当输入完查询条件后,如果需要通过鼠标点击"查询"按钮才发起查询,那么就感觉不够方便,那么我们就可以修改为按下回车键的时候发起查询. <sc ...
- JDBC入门案例
什么是JDBC? JDBC的全称是Java数据库连接(Java Database Connectivity),它是一套用于执行SQL语句的Java API. 作为一个Web开发人员来说,JDBC操作是 ...
- JavaScript的注意事项
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- IP地址与,域名,DNS服务器,端口号的联系与概念
一,什么是IP地址? 每一个联入到Internet的计算机都需要一个世界上独一无二的IP地址,相当于人们的身份证号码! IP地址有A类,B类,C类,D类和E类之分,目前D类和E类都暂时作为保留地址! ...
- 订阅 如何在IntelliJ IDEA中使用.ignore插件忽略不必要提交的文件
如何在IntelliJ IDEA中使用.ignore插件忽略不必要提交的文件 标签: idea git 插件 分类: Git 最近初学Git,而且在使用的IDE是IntelliJ IDEA,发现IDE ...
- Leetcode914.X of a Kind in a Deck of Cards卡牌分组
给定一副牌,每张牌上都写着一个整数. 此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组: 每组都有 X 张牌. 组内所有的牌上都写着相同的整数. 仅当你可选的 X > ...
- MySQL——外键
概念 关键字:foreign key,也叫做外键约束! 如果一个实体A的某个字段,刚好指向另一个实体B的主键,那么实体A的这个字段就叫做外键: 所以,简单来说,外键就是本表的某个字段指向外表的主键! ...