HDU 6795 Little W and Contest(2020杭电多校第三场)

Little W and Contest
Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1220 Accepted Submission(s): 407

Problem Description
There are n members in our ACM club. Little W wants to select three persons from our club to form a new team taking part in provincial ACM contests, as it is known by all of us that any ACM contest requires a normal team to have three members.

Little W has divided our club members into two role groups. The first group contains only readers who dedicate themselves to reading problems during contests, though sometimes they may also prepare drinking and food for the team. For the sake of measurement, we define the power of a reader as 1. The second part contains only coders who code and test programs all the time, and similarly, we define the power of a coder as 2.

Little W thinks it will be a tremendous disaster when a team has two readers because in that case, the total power of this team is less than 5 and thus it has a high risk to fail the contest. To avoid that, Little W thinks a new team must have at least two coders.

Additionally, Little W defines the relationship between club members with transitivity. That is, for every three members A, B, and C, if A is familiar with B, and B is familiar with C, then A will be familiar with C through B instantly. Based on the definition, it is forbidden for the team to have any two members familiar with each other.

At first, no member of our club is familiar with any other, and then Little W will repeatedly make an introduction between two members who are currently strangers to each other until each member is familiar with all the others. During this process, there will be exactly (n−1) introductions.

Now, for i=1,2,…,n, Little W wants you to count the combinations of three club members that can form a new team after the first (i−1) introductions have been made. However, the numbers of combinations may be quite gigantic, so you just need to report each number in modulo (109+7).

Input
There are several test cases.

The first line contains an integer T (1≤T≤10), denoting the number of test cases. Then follow all the test cases.

For each test case, the first line contains an integer n (1≤n≤105), denoting the number of members in this club.

The second line contains n integers consisting of only 1 and 2, where the i-th integer represents the power of the i-th member.

The next (n−1) lines describe all introductions in chronological order of occurrence, where each line contains two integers u and v (1≤u,v≤n,u≠v), representing an introduction between the u-th member and the v-th member, who are currently strangers to each other.

It is guaranteed that the sum of n is no larger than 106.

Output
For each test case, output n lines, where the i-th line contains an integer, denoting the number of combinations of three club members, in modulo (109+7), that can form a new team after the first (i−1) introductions have been made.

Sample Input

1
5
2 2 2 1 1
4 5
1 4
2 1
3 2
 

Sample Output

7
7
3
0
0
 

Code:
显而易见是用并查集,考虑在x,y这两个人认识后对答案的影响。
总组合数为:
num2*(num2-1)(num2-2)/6+num2(num2-1)*num1/2;

当把三块分出来,我们可以捋清楚了以下四个情况,每次合并排除这四种情况即可:
2 2 2 的组合两个2在集合内,一个2在集合外
2 2 1 的组合两个2在集合内,一个1在集合外
2 1 2 的组合集合外集合内分别一个2,一个1在集合内
1 2 2 的组合集合外集合内分别一个2,一个1在集合内

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#define ll long long
using namespace std;
const int INF=0x3f3f3f3f;
const double pi=acos(-1.0),eps=1e-8;
const int maxn=1e5+10;
const ll mod=1e9+7;
int f[100005],a[100005];
int cnt1[100005],cnt2[100005];
int find(int x)
{
    if(f[x]==x)
        return x;
    else
    {
        f[x]=find(f[x]);
        return f[x];
    }
}
void merge(int x,int y)
{
    int t1=find(x),t2=find(y);
    if(t1!=t2)
    {
        cnt1[t2]+=cnt1[t1];
        cnt2[t2]+=cnt2[t1];
        f[t1]=t2;
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        memset(cnt1,0,sizeof(cnt1));
        memset(cnt2,0,sizeof(cnt2));
        ll num1=0,num2=0;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            f[i]=i;
            scanf("%d",&a[i]);
            if(a[i]==1)
            {
                num1++;
                cnt1[i]=1;
            }
            if(a[i]==2)
            {
                num2++;
                cnt2[i]=1;
            }
        }
        ll ans=num2*(num2-1)*(num2-2)/6+num2*(num2-1)*num1/2;
        printf("%lld\n",ans%mod);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            int u,v;
            u=find(x);
            v=find(y);
            // 2 2 2 的组合两个2在集合内,一个2在集合外
            ans-=cnt2[u]*cnt2[v]*(num2-cnt2[u]-cnt2[v]);
            // 2 2 1 的组合两个2在集合内,一个1在集合外
            ans-=cnt2[u]*cnt2[v]*(num1-cnt1[u]-cnt1[v]);
            // 2 1 2 的组合集合外集合内分别一个2,一个1在集合内
            ans-=cnt2[u]*cnt1[v]*(num2-cnt2[u]-cnt2[v]);
            // 1 2 2
            ans-=cnt1[u]*cnt2[v]*(num2-cnt2[u]-cnt2[v]);

            merge(u,v);
            printf("%lld\n",ans%mod);
        }
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值