题解
题意:
第一行输入两个数
问最少还需要比较多少次才能确定一个数是第二大的数
数据范围:
思考:
什么数可能是第二大的数不太好找,那就考虑正难则反,求什么数不能成为第二大的数,剩下的自然是可能成为第二大的
显然的:当
考虑时间复杂度,排除
等等,图?
输入
套路的,我们可以用
这样就能保证不重不漏地把每一个不可能成为第二大的数筛掉,这很好证明,读者可以自己尝试一下
无视掉已经被排除的点,得到这样一张图:
可以发现是很多棵一层树,也就是每个
考虑只有一棵树,那么显然次数是
不难想到,每次比较子节点最小的两棵子树一定不劣(可以用调整法证明),那么就
AC代码
#include<bits/stdc++.h>
using namespace std;
int n,m,cnt,head[1000005],fa[1000005],bz[1000005],a[1000005],ans;
bool vis[1000005];
struct edge{
int to,nextt;
}edge[1000005];
priority_queue<int,vector<int>,greater<int>> q;
int in(){int k=0,f=1;char c=getchar();while (c<'0'||c>'9'){if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9'){k=k*10+c-'0';c=getchar();}return k*f;}
void addedge()
{
int x=in(),y=in();
fa[y]=x;
bz[y]++;
cnt++;
edge[cnt].to=y;
edge[cnt].nextt=head[x];
head[x]=cnt;
}
void solve(int z)
{
vis[z]=true;
for (int i=head[z];i;i=edge[i].nextt)
{
bz[edge[i].to]=2;
if (!vis[edge[i].to])
{
solve(edge[i].to);
}
}
}
signed main()
{
n=in();m=in();
for (int i=1;i<=m;i++)
{
addedge();
}
for (int i=1;i<=n;i++)
{
if (!vis[i]&&bz[i]>0)
{
solve(i);
}
}
for (int i=1;i<=n;i++)
{
if (bz[i]==1)
{
a[fa[i]]++;
}
}
for (int i=1;i<=n;i++)
{
if (!bz[i])
{
ans++;
q.push(a[i]);
}
}
while (q.size()>1)
{
q.pop();
q.push(q.top()+1);
q.pop();
}
cout<<q.top()-1+ans-1;
return 0;
}
时间复杂度
当然可以用合并果子的思想优化到