题目链接、
直接求四个不同的相乘不好求,那么维护三个的两个的和一个的,通过这三个来维护每次合并两个(删掉两个加上一个)造成的影响
注意一开始的直接算的话爆掉longlong了,所以处理了一下
影响:
一二三四个,记为cot1+cot2+cot3+cot4,其中cot4即答案
为了方便,我自己创造了俩符号,用来方便思考和叙述,
表示不去重的,即选出n个中选出i个相乘(有顺序的)
表示在中去掉造成的影响
表示在中加上造成的影响(原先并不存在)
,,
自己和自己并不需要相乘,那么统计和即可,去掉一个数,显然直接减掉,加上亦然
,,
显然可以通过来降低的复杂度
,,
一样,抄过来,改
,,
一样,抄过来,改
注意到,去重后的,即,也就是无顺序的,也就是除掉一个就好了。(就和排列组合类似的)
并不影响加一个和减一个数的具体操作,所以,我们一开始处理好,然后还是按照这个加加减减的方式进行处理就行了
尽管上面啰啰嗦嗦写了一堆乱七八糟的鬼话,但是结论挺简单的
减掉k
cot1 -= k;
cot2 -= k*cot1;
cot3 -= k*cot2;
cot4 -= k*cot3;
加上k
cot4 += k*cot3;
cot3 += k*cot2;
cot2 += k*cot1;
cot1 += k;
这个可以往上接着写cot5,cot6之类的
/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
typedef long long ll;
int Fa[maxn];
ll Size[maxn];
ll cot1,cot2,cot3,cot4;
int Find(int x){
return Fa[x]==x?x:Fa[x]=Find(Fa[x]);
}
void add(ll k){
cot4 += k*cot3;
cot3 += k*cot2;
cot2 += k*cot1;
cot1 += k;
}
void del(ll k){
cot1 -= k;
cot2 -= k*cot1;
cot3 -= k*cot2;
cot4 -= k*cot3;
}
int main(){
ll n,m;
scanf("%lld%lld",&n,&m);
cot1 = cot2 = cot3 = cot4 = 0;
for(int i=1;i<=n;i++)Size[i] = 1,Fa[i] = i,add(1LL);
printf("%lld\n",cot4);
while(m--){
int x,y;
scanf("%d%d",&x,&y);
x = Find(x),y = Find(y);
if(x == y){
printf("%lld\n",cot4);
}else{
ll k1 = Size[x] , k2 = Size[y];
del(k1),del(k2),add(k1+k2);
Fa[x] = y;
Size[y] += Size[x];
printf("%lld\n",cot4);
}
}
return 0;
}