首页 技术 正文
技术 2022年11月19日
0 收藏 391 点赞 4,483 浏览 3768 个字

题目传送门(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;
}


相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,075
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,551
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,399
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,176
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,811
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,893