题目传送门(luogu)

题目传送门(loj)

这个题对我来说可以算是超出了我的能力范围

被学长拿来教我做构造,构造题真简单,构造题真是人,构造题真能手切。。。

首先对于本题,必须要知道dfs树这东西,就是在一个图中得到一个树,

简单来说就是吧所有的边分成树边和非树边,所有的n-1个树边会把所有点连接成一颗树

这个在实现上就是一个dfs就好了

这里有一个小小的性质,在一个dfs树中,所有的非树边一定不是横叉边

意思就是所有的边连接的两个点一定是祖先后代关系

那么这个题就可以做了

你会发现这a,b,c并没有特殊的要求,所以我们选择这其中较小的那两个一定是优的

所以我们直接扔掉最大的那个,这时候你会发现

为了保证我们很顺利的找到答案,我们必须要找到树的重心,

因为在重心两侧,子树的大小一定小于等于\(\frac{n}{2}\),而a,b的大小又小于等于\(\frac{n}{3}\)

这样的话,我们只要保存这个重心,我们可以任意连接子树,从而一定可以满足\(a,b\)的其中一个

而剩下的子树中的节点数又一定大于a,这样为我们找到答案提供了很大的方便

那么我们一定先满足\(b\),因为我们要是想凑出a来一定是比b更容易,那么我们接下来的重点就是要找a

首先我们看\(m=n-1\)的情况,这样的话本来就是一棵树,直接找到重心,判断是不是有子树的大小大于a,如果有 ,那么就有解,没有的话,就无解呗

因为你没有别的边可以连接另外的子树,所以你当前的子树就你你可以找到的所有可以作为a的联通块

而b可以通过重心连接,不需要考虑

那么这时候你会发现,如果是图的话,那就可以有别的边来连接??虽然不可以连接在dfs树上的子树,

但是别忘了,在dfs树上,它的祖先也是他的子树,所以我们只要不断的去连接和它祖先有连边的子树,并且将大小加和

如果能够得到一个大小为a的联通块,那就有解,当然这时候你并没有选重心,b仍然是合法的

我们来看这里的重心有什么用,这个重心首先保证了你有一堆大小\(<=\frac{n}{2}\)的子树

这样的话,你一定可以凑出一个b来,而重心又在一定程度上帮你将整张图分为两部分

一个是那一堆子树,一个是祖先那边的节点,这就是构造的意义所在

构造你想要的条件来解决一般问题

还有一些要注意的情况,

有可能在图中,你并不能找到合法的反祖边,但是呢,有一颗子树的大小是合法的,

这个时候就要向树的做法一样了,我要去判断一下每一颗子树的大小

还有输出的时候,千万不要找到一颗子树就开始从他的根节点遍历

因为你是从有和祖先连边的那个点出发才可以联通的啊,要从他开始

我的代码中imp这个数组就是干这个活的

AC_code

#include <bits/stdc++.h>
using namespace std;
#define re register int
const int N = 1e5 + 5;
const int M = 2e5 + 5;
int n, m;
pair<int, int> a[4];
int fr[M * 2], to[M * 2], nxt[M * 2], head[N], rp = 1;
void add_edg(int x, int y) {
to[++rp] = y;
fr[rp] = x;
nxt[rp] = head[x];
head[x] = rp;
}
int fa[N], dep[N], siz[N], rt, mn = 0x3f3f3f3f;
bool vis[N], pd[M * 2];
void dfs(int x) {
vis[x] = true;
siz[x] = 1;
int mx = 0; for (re i = head[x]; i; i = nxt[i]) {
int y = to[i]; if (vis[y])
continue; fa[y] = x;
pd[i] = pd[i ^ 1] = true;
dep[y] = dep[x] + 1;
dfs(y);
siz[x] += siz[y]; if (siz[y] > mx)
mx = siz[y];
} if (n - siz[x] > mx)
mx = n - siz[x]; if (mx < mn)
mn = mx, rt = x;
}
int imp[N], bl[N], sz[N];
void change(int x, int b) {
bl[x] = b;
sz[b]++; for (re i = head[x]; i; i = nxt[i]) {
int y = to[i]; if (dep[y] != dep[x] + 1)
continue; change(y, b);
}
}
int ji[N], cnt;
int ans[N];
void biao1(int x) {
if (cnt == a[1].first)
return ; ans[x] = a[1].second;
cnt++; for (re i = head[x]; i; i = nxt[i]) {
int y = to[i]; if (y == rt || dep[y] != dep[x] + 1)
continue; biao1(y);
}
}
void biao2(int x, int f) {
if (cnt == a[1].first || ans[x])
return ; ans[x] = a[1].second;
cnt++; for (re i = head[x]; i; i = nxt[i]) {
int y = to[i]; if (bl[y] != f || ans[y])
continue; biao2(y, f);
}
}
void biao3(int x) {
if (cnt == a[2].first)
return ; ans[x] = a[2].second;
cnt++; for (re i = head[x]; i; i = nxt[i]) {
int y = to[i]; if (dep[y] != dep[x] + 1)
continue; biao3(y);
}
}
signed main() {
scanf("%d%d", &n, &m);
scanf("%d%d%d", &a[1].first, &a[2].first, &a[3].first);
a[1].second = 1;
a[2].second = 2;
a[3].second = 3;
sort(a + 1, a + 4); for (re i = 1, x, y; i <= m; i++) {
scanf("%d%d", &x, &y);
x++;
y++;
add_edg(x, y);
add_edg(y, x);
} dfs(1);
siz[0] = n - 1; //cout<<rt<<endl;
for (re i = head[rt]; i; i = nxt[i]) {
int y = to[i]; if (y == fa[rt] || dep[y] != dep[rt] + 1)
continue; change(y, y);
//cout<<rt<<" "<<y<<" "<<siz[0]<<" "<<siz[y]<<endl;
siz[0] -= sz[y];
} //cout<<rt<<" "<<siz[rt]<<" "<<siz[0]<<endl;
for (re i = 2; i <= rp; i += 2) {
if (pd[i])
continue; //cout<<"sb"<<endl;
if (siz[0] >= a[1].first)
break; int u = fr[i], v = to[i]; //cout<<bl[u]<<" "<<bl[v]<<endl;
if (bl[u] && bl[v])
continue; if (!bl[u] && !bl[v])
continue; //cout<<u<<" "<<v<<" "<<siz[bl[u]]<<" "<<siz[bl[v]]<<endl;
if (bl[u] && !ji[bl[u]] && (v != rt || siz[0] == 0)) {
ji[bl[u]] = 1;
imp[bl[u]] = u;
siz[0] += sz[bl[u]];
} if (bl[v] && !ji[bl[v]] && (u != rt || siz[0] == 0)) {
ji[bl[v]] = 1;
imp[bl[v]] = v;
siz[0] += sz[bl[v]];
}
} //cout<<siz[0]<<endl;
int flag = 0; if (siz[0] < a[1].first) {
for (re i = head[rt]; i; i = nxt[i]) {
int y = to[i]; if (dep[y] != dep[rt] + 1)
continue; if (siz[y] >= a[1].first) {
siz[0] = siz[y];
ji[y] = 1;
imp[y] = y;
flag = 1;
break;
}
}
} if (siz[0] >= a[1].first) {
cnt = 0; if ((rt != 1 && !flag))
biao1(1); for (re i = head[rt]; i; i = nxt[i]) {
int y = to[i]; if (!ji[y] || dep[y] != dep[rt] + 1)
continue; if (cnt >= a[1].first)
break; biao2(imp[y], y); //cout<<siz[y]<<endl;
} cnt = 1;
ans[rt] = a[2].second; for (re i = head[rt]; i; i = nxt[i]) {
int y = to[i]; if (ji[y] || dep[y] != dep[rt] + 1)
continue; if (cnt >= a[2].first)
break; biao3(y);
}
} //cout<<a[1].second<<endl;
for (re i = 1; i <= n; i++) {
if (siz[0] >= a[1].first && !ans[i])
ans[i] = a[3].second; printf("%d ", ans[i]);
} //cout<<p<<endl;
}


<题解>[IOI2019]景点划分的更多相关文章

  1. 【题解】整数划分 [51nod1201] 整数划分 V2 [51nod1259]

    [题解]整数划分 [51nod1201] 整数划分 V2 [51nod1259] 传送门:整数划分 \([51nod1201]\) 整数划分 \(V2\) \([51nod1259]\)** [题目描 ...

  2. 题解 [51nod1201] 整数划分

    题面 解析 首先,因为是不同的数字, 可以从小到大依次枚举加上每一个数字的贡献,再枚举每个数. 然而这样会T掉... 考虑到\(n\)只有\(50000\), 当分成的数最多时,设最大的数为\(m\) ...

  3. [loj3176]景点划分

    不妨设$a\le b\le c$,那么相当于要找到两个大小至少为$a$和$b$的连通块(连通块可以通过删除度最小的点变小) 以一个点为根建出dfs树并对以下情况分类讨论: 1.存在一个节点满足$\ma ...

  4. world.construct(me);

    目录 0 引言 0.1 所谓构造题 0.2 重点是动机 (motivation) 1 实践出真知 1.1 「CSP-S 2021」「洛谷 P7915」回文 1.1.1 题目大意 1.1.2 解题过程 ...

  5. HDU 2665 Kth number(可持续化线段树)

    Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  6. HDU 3966 Aragorn's Story 树链剖分+BIT区间修改/单点询问

    Aragorn's Story Description Our protagonist is the handsome human prince Aragorn comes from The Lord ...

  7. 题解 洛谷 P4047 【[JSOI2010]部落划分】

    我觉得几乎就是一道最小生成树模板啊... 题解里许多大佬都说选第n-k+1条边,可我觉得要这么讲比较容易理解 (虚边为能选的边,实边为最小生成树) 令n=5,k=2,(1,3)<(1,2)< ...

  8. 洛谷P4047 [JSOI2010]部落划分题解

    洛谷P4047 [JSOI2010]部落划分题解 题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落 ...

  9. CF1238E.Keyboard Purchase 题解 状压/子集划分DP

    作者:zifeiy 标签:状压DP,子集划分DP 题目链接:https://codeforces.com/contest/1238/problem/E 题目大意: 给你一个长度为 \(n(n \le ...

随机推荐

  1. DB2 SQL0805N解决和思考

    一.报错现象 这是一个在使用 DB2数据库过程中比较常见的错误, 报错信息如下 Exception stack trace: com.ibm.db2.jcc.am.SqlException: DB2 ...

  2. Java知识复习(三)

    Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?用contains来区分是否有重复的对象.还是都不用. 在比较时先调用hashCode方法, ...

  3. golang 模板语法使不解析html标签及特殊字符

    场景 有时候需要使用go的模板语法,比如说用go 去渲染html页面的时候,再比如说用go的模板搞代码生成的时候.这时候可能会遇到一个麻烦,不想转译的特殊字符被转译了. 我遇到的情况是写代码生成器的时 ...

  4. 图解 Redis | 差点崩溃了,还好有主从复制

    大家好,我是小林哥,又来图解 Redis 啦. 我在前两篇已经给大家图解了 AOF 和 RDB,这两个持久化技术保证了即使在服务器重启的情况下也不会丢失数据(或少量损失). 不过,由于数据都是存储在一 ...

  5. Pycharm破解版_安装从失败到成功

    前言: 入门学习的时候一直用的是社区版的,现在想换个专业版的玩玩. 本文使用的环境说明: win10系统 安装过pycharm社区版,已卸载 已安装python 3.8.5 (建议看完整篇文章后再自行 ...

  6. cURL命令使用指南

    cURL是什么 curl是Linux命令行工具,可以使用任何可支持的协议(如HTTP.FTP.IMAP.POP3.SCP.SFTP.SMTP.TFTP.TELNET.LDAP或FILE)在服务器之间传 ...

  7. Redis之阻塞分析

    Redis是典型的单线程架构,所有的读写操作都是在一条主线程中完成的.当Redis用于高并发场景时,这条线程就变成了它的生命线.如果出现阻塞,哪怕是很短时间,对于我们的应用来说都是噩梦.导致阻塞问题的 ...

  8. Linux中useradd的用法

    语法:useradd [选项] 用户名 选项: -d<登陆目录> 指定新用户登陆的起始目录,默认为/home -e<有效期限> 指定用户的有效期限,格式为 YYYY-MM-DD ...

  9. 4、nfs服务器的搭建

    4.1.nfs服务介绍: samba服务器一般互联网企业不会使用 nfs服务的端口是不固定的,需要先启动rpc服务对nfs服务端口进行注册 4.2.安装nfs: rpm -qa nfs-utils r ...

  10. vsftp安装错误总结

    1.vsftpd 530 Login incorrect 解决办法:将用户从/etc/vsftpd/ftpusers  中删除 参考:http://blog.51yip.com/linux/1672. ...