LOJ3176「IOI2019」景点划分分析性质,构造
Posted AThousandMoons
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LOJ3176「IOI2019」景点划分分析性质,构造相关的知识,希望对你有一定的参考价值。
给定 \\(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);
}
以上是关于LOJ3176「IOI2019」景点划分分析性质,构造的主要内容,如果未能解决你的问题,请参考以下文章
loj 3217 「PA 2019」Desant - 动态规划 - 复杂度分析