题目描述
小强和阿米巴是好朋友。小强要出一套题目。
他的题目以涉及面广(偏)、考察深入(怪)、思维强度大(难)著称。他为了出题,一共攒了M个本质不同的想法,每个想法形成了一个题目。不过,他觉得拿这些题目去考察选手会把比赛搞的太过变态,所以,想请阿米巴来帮忙调整一下他的题目。
阿米巴指出,为了让一场考试的题目的考察点尽量全面,有一个通用的做法叫做“组合”。如果把两个题目A和B组合在一起,那么组合而成的题目涉及到的想法的集合就是A涉及到的想法的集合和B涉及到的想法的集合的并。并且,题目是可以反复组合的。
例如,小强现在有三个想法1,2,3,分别对应了题目P1,P2,P3。
现在,小强把P1和P2组合得到P4。P4涉及的想法的集合是{1,2}。
之后,小强把P2和P3组合得到P5。P5涉及的想法的集合是{2,3}。
最后,小强把P4和P5组合得到P6。P6涉及的想法的集合是{1,2,3}。
现在,小强告诉你每个题目都是如何组合而来的。你要回答的就是,每个题目涉及的想法的集合有多大。
不过,这个问题是很难的。于是,你只需要能够以比较高的概率回答的比较准确即可。
输入输出格式
输入格式:
第一行两个整数N,M,依次表示小强的题目数量和想法的数量
接下来N-M行,每行两个整数,依次表示小强组合出来的题目都是由哪两个题组合而成的。M个想法对应的题目依次编号为1~M。之后,小强组合来的第一个题编号为M+1,组合出来的第二个题编号为M+2,依次类推。
M≤100000,N≤1000000
输出格式:
输出N-M行,每行一个整数表示小强组合出来的每个题都涉及了几个想法。
输入输出样例
输入样例#1:
6 3
1 2
2 3
4 5
输出样例#1:
2
2
3
说明
【评分方法】
对于每个输出文件,如果其中你有95%以上的行的答案和正确答案的误差不超过25%,那么你就可以得到分数。所谓误差不超过25%,即,如果正确答案是X,那么你的答案在[0.8X,1.25X]这个闭区间内。
分析:
我们给每个想法从[1,randmax][1,randmax][1,randmax]随机一个权值,每个题相当于一个数集。
显然我们不能记录所有数,我们只记下前kkk小的数。
处理合并就是把两个数集归并,不过不能有重复(只有个两个权值相同且属于同一个想法才要去掉)。
假如数集大小小于kkk,直接输出数集大小。
否则假设第kkk小的数是xxx,有
kx=ansrandmax\frac{k}{x}=\frac{ans}{randmax}xk=randmaxans
我们设k=50k=50k=50,多跑几次求平均值即可。
代码:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstdlib>
#define LL long long
const int maxn=1e6+7;
const int randmax=1e8+7;
const int k=50;
using namespace std;
int a[maxn];
LL ans[maxn];
int f[maxn][51];
int q[maxn][2];
int n,m;
int random(int n)
{
return (long long)rand()*rand()%n;
}
void merge(int x,int y,int d)
{
int i=1,j=1,num=0;
while (((f[x][i]) || (f[y][j])) && (num<k))
{
if (a[f[x][i]]<a[f[y][j]])
{
if (f[d][num]!=f[x][i]) f[d][++num]=f[x][i];
i++;
}
else
{
if (f[d][num]!=f[y][j]) f[d][++num]=f[y][j];
j++;
}
}
f[d][0]=num;
}
int main()
{
scanf("%d%d",&n,&m);
a[0]=randmax;
for (int i=m+1;i<=n;i++) scanf("%d%d",&q[i][0],&q[i][1]);
for (int T=1;T<=4;T++)
{
for (int i=1;i<=n;i++) a[i]=random(randmax)+1;
for (int i=1;i<=m;i++)
{
f[i][0]=1;
f[i][1]=i;
for (int j=2;j<=k;j++) f[i][j]=0;
}
for (int i=m+1;i<=n;i++)
{
merge(q[i][0],q[i][1],i);
if (f[i][0]<k) ans[i]=(LL)f[i][0]*4;
else ans[i]+=(LL)k*(LL)randmax/(LL)a[f[i][k]];
}
}
for (int i=m+1;i<=n;i++) printf("%lld\n",ans[i]/4);
}