一.题目链接:

All men are brothers

二.题目大意:

n 个人,m 次操作.

每次操作让两个人交朋友,朋友关系互逆且可传递.

每次操作后,输出四人组的种数,使得这四个人中每每两个人均不为朋友.

三.分析:

并查集很容易想到,这题其实可以用组合数学来解的,可惜我太菜,不会。。。

这里用线段树写一下.

tree[i][j] 代表第 i 个节点所包含的区间内,从中选出 j 个人且两两不为朋友的方案数.

详见代码.

四.代码实现:

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
using namespace std;

const int M = (int)1e5;
const int mod = 99991;
const int inf = 0x3f3f3f3f;

ll tree[M * 4 + 5][5];
int fa[M + 5], sz[M + 5];

int tofind(int x)
{
    if(x != fa[x])
        fa[x] = tofind(fa[fa[x]]);
    return fa[x];
}

void push_up(int k)
{
    tree[k][1] = tree[lc][1] + tree[rc][1];
    tree[k][2] = tree[lc][1] * tree[rc][1] + tree[lc][2] + tree[rc][2];
    tree[k][3] = tree[lc][1] * tree[rc][2] + tree[lc][2] * tree[rc][1]
    + tree[lc][3] + tree[rc][3];
    tree[k][4] = tree[lc][1] * tree[rc][3] + tree[lc][3] * tree[rc][1] 
    + tree[lc][2] * tree[rc][2] + tree[lc][4] + tree[rc][4];
}

void build(int k, int l, int r)
{
    if(l == r)
    {
        tree[k][1] = 1;
        tree[k][2] = tree[k][3] = tree[k][4] = 0;
        return;
    }
    int mid = (l + r) >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
    push_up(k);
}

void update(int k, int l, int r, int pos, int v)
{
    if(l == r)
    {
        tree[k][1] = v;
        tree[k][2] = tree[k][3] = tree[k][4] = 0;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid)
        update(lc, l, mid, pos, v);
    else
        update(rc, mid + 1, r, pos, v);
    push_up(k);
}

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; ++i)
        fa[i] = i, sz[i] = 1;
    int u, v;
    build(1, 1, n);
    printf("%lld\n", tree[1][4]);
    while((m--) > 0)
    {
        scanf("%d %d", &u, &v);
        u = tofind(u);
        v = tofind(v);
        if(u != v)
        {
            fa[v] = u;
            sz[u] += sz[v];
            update(1, 1, n, v, 0);
            update(1, 1, n, u, sz[u]);
        }
        printf("%lld\n", tree[1][4]);
    }
    return 0;
}