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;
}
标签:cnt,vis,int,POI2008MAF,len,++,Mafia,deg
From: https://www.cnblogs.com/xiaruize/p/18136779