1. 程式人生 > 實用技巧 >Little W and Contest HDU - 6795

Little W and Contest HDU - 6795

Parctice link:https://vjudge.net/problem/HDU-6795

Problem Description

There arenmembers 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 as1. The second part contains only coders who code and test programs all the time, and similarly, we define the power of a coder as2
.

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 than5and 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 membersA
,B, andC, ifAis familiar withB, andBis familiar withC, thenAwill be familiar withCthroughBinstantly. 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(n1)introductions.

Now, fori=1,2,,n, Little W wants you to count the combinations of three club members that can form a new team after the first(i1)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 integerT(1T10), denoting the number of test cases. Then follow all the test cases.

For each test case, the first line contains an integern(1n105), denoting the number of members in this club.

The second line containsnintegers consisting of only1and2, where thei-th integer represents the power of thei-th member.

The next(n1)lines describe all introductions in chronological order of occurrence, where each line contains two integersuandv(1u,vn,uv), representing an introduction between theu-th member and thev-th member, who are currently strangers to each other.

It is guaranteed that the sum ofnis no larger than106.

Output

For each test case, outputnlines, where thei-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(i1)introductions have been made.

題意:給你 n 個人,這 n 個人有 1 或者 2 的權值,再給你分別給你 n - 1條邊,你需要在這 n 個人中挑選 3 個人,且這三個人的權值總和大於等於5,並且這三個人在圖上是不連通的,問你每新增一條邊,可以挑選的總方案數分別是多少。

思路:首先,考慮沒有邊時,我們假設 cnt1 是擁有權值為 1 的人的數量,cnt2是擁有權值 2 的人的數量,那麼初始方案就是

ans=C(2,cnt2)*C(1,cnt1)+C(3,cnt2)

接下來就要考慮有邊的情況,首先 設 p1[ i ] 是以 i 為根節點的連通塊的 1 的權值的人的數量, p2[ i ]就是以 i 為根節點的連通塊的 2 的權值的人的數量。然後引入一條邊(u,v)時,設三個集合 G( u )即以u為根節點的連通塊,G( v )時以 v 為根節點的連通塊,G( r )是其他連通塊,那麼引入這條邊後,就有一些方案不能成立,就是三個人分別屬於G( u)、G( v )和G( r )的情況。也就是(2、2、1)、(2、2、2)、(1、2、2)和(2、1、2)四種情況,依次減去這四種情況,就是在新增這條邊後的方案數,最後用並查集合並兩個點所在的連通塊。

程式碼:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define INF 0x3f3f3f3f
 4 #define mem(a,x) memset(a,x,sizeof(a))  
 5 #define _for(i,a,b) for(int i=a; i< b; i++)
 6 #define _rep(i,a,b) for(int i=a; i<=b; i++)
 7 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 8 using namespace std;
 9 const int MOD = 1e9+7 ;
10 const int maxn = 100005 ;
11 
12 int fa[maxn];
13 int p1[maxn],p2[maxn];   //以i為根的連通塊含1 和含2 
14 int a[maxn];
15 int n;
16 ll ans=0;
17 int find(int x)
18 {
19   return (fa[x]==x)?x:(fa[x]=find(fa[x]));
20 }
21 
22 int main()
23 {
24     int T;
25     scanf("%d",&T);
26     while(T--){
27       ll x=0,y=0;
28       ans=0;
29       scanf("%d",&n);
30       for(int i=1;i<=n;i++){
31         scanf("%d",&a[i]);
32         if(a[i]==1){
33           x++;
34           p1[i]=1;
35           p2[i]=0;
36         }
37         if(a[i]==2){
38           y++;
39           p1[i]=0;
40           p2[i]=1;
41         }
42         fa[i]=i;
43       }
44       ans=(ll)(y*(y-1)/2)*x+(ll)(y*(y-1)*(y-2))/6;
45       ans=ans%MOD;
46       printf("%lld\n",ans);
47       for(int i=1;i<n;i++){
48           int u,v;
49           ll k=0;
50           scanf("%d %d",&u,&v);
51           int pu=find(u),pv=find(v);
52           k=(k+(ll)(p2[pu]*p2[pv])*(y-p2[pu]-p2[pv]))%MOD;
53           k=(k+(ll)(p2[pu]*p1[pv])*(y-p2[pu]-p2[pv]))%MOD;
54           k=(k+(ll)(p1[pu]*p2[pv])*(y-p2[pu]-p2[pv]))%MOD;
55           k=(k+(ll)(p2[pu]*p2[pv])*(x-p1[pu]-p1[pv]))%MOD;
56           ans=(ans-k+MOD)%MOD;
57           printf("%lld\n",ans);
58           fa[pv]=pu;
59           p1[pu]+=p1[pv];
60           p2[pu]+=p2[pv];
61       }
62 
63     }
64     return 0;
65 }
View Code