Always keep|

园龄:粉丝:关注:

POI2008MAF-Mafia

POI #基环树 #贪心 #Year2008

一定是若干棵基环内向树,以下仅考虑一棵的情况

最小值直接从下往上选,然后环上的为环的 siz 的一半

最大值为 n 减去叶子个数,再特判环上剩下一个的情况

// Author: xiaruize
const int N = 1e6 + 10;
int n;
int a[N];
int deg[N];
int cnt = 0, res = 0;
queue<int> q;
bool fl[N];
bool vis[N];
void solve()
{
cin >> n;
rep(i, 1, n)
{
cin >> a[i];
deg[a[i]]++;
}
queue<int> q;
rep(i, 1, n)
{
if (!deg[i])
{
q.push(i);
cnt++;
res++;
}
}
while (!q.empty())
{
int x = q.front();
q.pop();
if (vis[a[x]])
continue;
vis[a[x]] = true;
deg[a[a[x]]]--;
fl[a[a[x]]] = true;
if (!deg[a[a[x]]])
{
q.push(a[a[x]]);
cnt++;
}
}
rep(i, 1, n)
{
if (deg[i] && !vis[i])
{
int x = i;
bool f = false;
int len = 0;
do
{
f |= fl[x];
len++;
vis[x] = true;
x = a[x];
} while (x != i);
if (!f && len > 1)
res++;
cnt += len / 2;
}
}
cout << n - cnt << ' ' << n - res << endl;
}
#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
#ifndef ONLINE_JUDGE
cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
return 0;
}

本文作者:xiaruize's Blog

本文链接:https://www.cnblogs.com/xiaruize/p/18136779

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   xiaruize  阅读(3)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起