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 }
题目链接: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 }
启发式并查集的时候 注意 f[x]=y 千万别写在swap之前了

浙公网安备 33010602011771号