ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LOJ3176「IOI2019」景点划分【分析性质,构造】

2021-06-14 13:03:12  阅读:191  来源: 互联网

标签:IOI2019 子树 int head le dfn low 景点 LOJ3176


给定 \(n\) 个点 \(m\) 条边的简单无向连通图和三个正整数 \(a,b,c\),求将点集划分为大小分别为 \(a,b,c\) 的集合 \(A,B,C\) 的方案,使得至少两个的导出子图连通。

\(n\le 10^5\),\(m\le 2\cdot 10^5\),\(a+b+c=n\)。


图连通性、构造 \(\rightarrow\) dfs 树。

不妨设 \(a\le b\le c\),则有 \(a\le\frac n3\),\(b\le\frac n2\),\(c\ge\frac n3\),问题转化为选取两个大小至少为 \(a,b\) 的连通导出子图(更大了可以剥叶子)

先看树的部分分怎么做:随便定个点 \(1\) 做根,其中一个连通子图可以是子树,那么只需要存在一个子树的大小 \(\in[a,n-a]\) 就可以了(若子树大小 \(\ge b\) 则子树对应大小 \(\ge b\) 的,否则对应大小 \(\ge a\) 的),构造方案就从割开的边向两边 dfs。

然后看原题:如果 dfs 树有解那么就做完了,否则找到一个最深的大小 \(>n-a\) 的子树(可以发现这样的子树只有一个),设根为 \(x\),删掉 \(x\) 之后 \(x\) 的儿子有一些子树,其中有些可以到 \(x\) 的子树之外,有些不行,那么必定要能到 \(x\) 的子树之外的子树大小之和+\(x\) 的子树之外的大小至少是 \(a\),因为另一个连通子图只能占这些,否则跟树的情况类似,一定有解,构造方案仍然是直接 dfs:\(x\) 先把自家势力范围占据完,不够再占共用范围,剩下的给另一个连通子图。

时间复杂度 \(O(n+m)\)。

#include<bits/stdc++.h>
#define MP make_pair
#define PB emplace_back
#define fi first
#define se second
using namespace std;
typedef pair<int, int> pii;
const int N = 100003, M = N<<2;
template<typename T>
void read(T &x){
	int ch = getchar(); x = 0;
	for(;ch < '0' || ch > '9';ch = getchar());
	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
template<typename T>
bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
int n, m, cnt, head[N], to[M], nxt[M];
pii a[3];
void add(int u, int v){to[++cnt] = v; nxt[cnt] = head[u]; head[u] = cnt;}
int dfn[N], low[N], tim, siz[N], sum[N], rem, ans[N];
void doit(int x, int col, bool flg){
	if(!rem || ans[x]) return;
	-- rem; ans[x] = col;
	for(int i = head[x];i;i = nxt[i])
		if(flg || dfn[to[i]] > dfn[x])
			doit(to[i], col, flg);
}
void dfs(int x, int f){
	siz[x] = sum[x] = 1;
	dfn[x] = low[x] = ++tim;
	for(int i = head[x];i;i = nxt[i]) if(to[i] != f){
		if(!dfn[to[i]]){
			dfs(to[i], x);
			siz[x] += siz[to[i]];
			if(low[to[i]] >= dfn[x])
				sum[x] += siz[to[i]];
			chmin(low[x], low[to[i]]);
		} else chmin(low[x], dfn[to[i]]);
	}
	if(siz[x] >= a[0].fi){
		if(sum[x] > n-a[0].fi){
			for(int i = 1;i <= n;++ i)
				printf("0 ");
			exit(0);
		}
		if(sum[x] > n-a[1].fi) swap(a[0], a[1]);
		rem = a[0].fi-1; ans[x] = a[0].se;
		for(int i = head[x];i;i = nxt[i])
			if(low[to[i]] >= dfn[x])
				doit(to[i], a[0].se, false);
		for(int i = head[x];i;i = nxt[i])
			if(dfn[to[i]] > dfn[x] && low[to[i]] < dfn[x])
				doit(to[i], a[0].se, false);
		rem = a[1].fi; doit(1, a[1].se, true);
		for(int i = 1;i <= n;++ i) printf("%d ", ans[i] ?: a[2].se);
		exit(0);
	}
}
int main(){
	read(n); read(m);
	for(int i = 0;i < 3;++ i){
		read(a[i].fi); a[i].se = i+1;
	}
	sort(a, a+3);
	for(int i = 0, u, v;i < m;++ i){
		read(u); read(v);
		add(++u, ++v); add(v, u);
	}
	dfs(1, 0);
}

标签:IOI2019,子树,int,head,le,dfn,low,景点,LOJ3176
来源: https://www.cnblogs.com/AThousandMoons/p/14882280.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有