C. Experience F - Confluence ###K ###K ###K //K

题目链接:https://codeforces.ml/edu/course/2/lesson/7/1/practice/contest/289390/problem/C   

题意:有n个人,刚开始各自为自己的队伍   同一个队伍的成员经验共享

有三种操作, 第一种操作是把X Y两队合并成一队 

第二种操作是 给队伍X 增加经验值 第三种操作是 查询玩家X 的当前经验值 

思路: 启发式合并    因为合并两组的时候 我们要用并查集来合并, 但是这样的贡献在个人中却有会多出来的
因为可能这个人还没加入这个队伍之前 这个队伍就已经加过贡献了, 为了处理这一点 考虑将个人的答案转为

ans=sum[i]+v[i] 即个人的贡献+上团队的贡献, 所以每次join的时候 要for 一遍 Y队伍中的人

把sum[i]=sum[i]+v[y]-v[x]  这样就能抵消掉多余的那部分, 然后要用到启发式合并 假设大集合X 小集合Y 

那么必须要 遍历小集合 才能够保证时间复杂度  没有分裂操作的话 启发式合并的时间复杂度是nlogn

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define pb push_back
 5 const int maxn =2e5+10;
 6 const int mod=1e9+7;
 7 int n,m;
 8 int f[maxn];
 9 int sum[maxn];
10 int v[maxn];
11 vector<int>E[maxn];
12 
13 int find1(int x)
14 {
15     if(x==f[x])
16         return f[x];
17     return f[x]=find1(f[x]);
18 }
19 
20 
21 
22 int main()
23 {
24     ios::sync_with_stdio(false);
25     cin.tie(0);
26     cin>>n>>m;
27     for(int i=1;i<=n;i++)
28         f[i]=i,E[i].pb(i);
29     while(m--)
30     {
31         string s;
32         cin>>s;
33         if(s[0]=='j')
34         {
35             int x,y;
36             cin>>x>>y;
37             x=find1(x),y=find1(y);
38             if(x==y)
39                 continue;
40             if(E[x].size()<E[y].size())
41                 swap(x,y);
42             for(auto &i:E[y])
43             {
44                 E[x].pb(i);
45                 sum[i]+=v[y]-v[x];
46             }
47             f[y]=x;
48         }
49         else if(s[0]=='a')
50         {
51             int x,y;
52             cin>>x>>y;
53             v[find1(x)]+=y;
54         }
55         else
56         {
57             int x;
58             cin>>x;
59             cout<<sum[x]+v[find1(x)]<<'\n';
60         }
61     }
62 
63 
64 
65 
66 
67 }
View Code

 

题目链接:https://atcoder.jp/contests/abc183/tasks/abc183_f

题意:每个人有一个班级  有2种询问 第一种是 将两组人合并

第二种是 询问班级y中有 x组的人多少个

启发式合并来写,  注意想的时候不要从 某个班级中找多少人是x组的下手 而是从x的集合中找多少个是y班的人

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define pb push_back
 4 using namespace std;
 5 const int maxn=2e5+10;
 6 const int mod=1e9+7;
 7 
 8 map<int,int>mp[maxn];
 9 int f[maxn];
10 vector<int>E[maxn];
11 
12 int find1(int x)
13 {
14     if(x==f[x])
15         return x;
16     return f[x]=find1(f[x]);
17 }
18 
19 void add(int x,int y)
20 {
21     int t1=find1(x),t2=find1(y);
22     f[t1]=t2;
23 }
24 
25 
26 int main()
27 {
28     ios::sync_with_stdio(0);
29     cin.tie(0);
30     int n,q;
31     cin>>n>>q;
32     for(int i=1;i<=n;i++)
33     {
34         f[i]=i;
35         int c;
36         cin>>c;
37         E[i].pb(c);
38         mp[i][c]++;
39     }
40     while(q--)
41     {
42         int t,x,y;
43         cin>>t>>x>>y;
44         if(t==1)
45         {
46             int t1=find1(x),t2=find1(y);
47             if(t1==t2)
48                 continue;
49             if(E[t1]>E[t2])
50                 swap(t1,t2);
51             for(auto &v:E[t1])
52             {
53                 E[t2].pb(v);
54                 mp[t2][v]++;
55             }
56             f[t1]=t2;
57         }
58         else
59             cout<<mp[find1(x)][y]<<'\n';
60     }
61 
62 
63 
64 }
View Code

 启发式并查集的时候 注意 f[x]=y  千万别写在swap之前了

posted @ 2020-11-04 21:45  canwinfor  阅读(52)  评论(0)    收藏  举报