码迷,mamicode.com
首页 > 其他好文 > 详细

小A的模拟军团——启发式合并

时间:2019-03-13 23:02:52      阅读:374      评论:0      收藏:0      [点我收藏+]

标签:总数   输入   tor   形式   c++   str   其他   输入格式   颜色不同   

小a的模拟军团

问题描述:

9102年伊始,小a觉得山羊模拟器,乞丐模拟器之类的都太低级了,所以想自己建立一个征战天下的军团模拟器。

军团模拟器是在一个城市数为N的国家中运行的,每个城市都会通过一些道路和其他所有城市相连,道路总数为N−1。 开始时,每个城市中都会有一个军队,每个军队有着自己的编号。

定义军团为相邻的同种编号军队的最大联通块,有些时候某种编号的军队会改变自己的编号,小a想要知道这些时候整个国家有多少军团。形式化的,我们会有Q次操作,每次操作为以下形式。

一行两个正整数a,b表示所有编号为a的军队编号变成b

输入格式:

第一行两个整数N,Q

接下来一行N个非负整数,表示初始时N个城市上军队的编号是多少,如果为0那么无军队。

接下来N−1行每行两个正整数u,v表示城市u和城市v之间有道路相连。

接下来Q行,两个整数x,y表示询问操作。

输出格式:

对于每次询问,输出一行一个整数,表示询问过后的军团数。

输入样例1:

5 2

1 1 3 2 2

1 2

1 3

2 4

2 5

3 2

2 1

输出样例1:

4

1

输入样例2:

5 6

1 2 3 4 9

1 2

2 3

3 4

4 5

1 2

2 1

2 3

1 3

3 4

4 5

输出样例2:

4

4

4

3

2

2

备注:

样例1解释:初始时共有四个军团,分别为{1,2}{3}{4}{5}

操作一使得3号节点的编号由3改为2,此时仍有四个军团

操作二使得4,5号节点的编号由2改为1,此时只有一个军团

数据范围:

    保证1<=N,Q,所有编号最大值<=200000

    保证输入数据合法

 

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. vector<int> v[200005],num[200005];
  4. int ans,col[200005],fa[200005];
  5. bool vis[200005];
  6. void dfs(int x){
  7.     vis[x]=true; //标记当前节点已访问
  8.     num[col[x]].push_back(x); //把颜色相同的节点放入一个数组中
  9.     for(int i=0;i<v[x].size();i++){ //与x相邻的所有节点now
  10.         int now=v[x][i];
  11.         if(!vis[now]){ //如果now没有访问过
  12.             //如果一个节点和他父节点颜色不同,答案就++
  13.             if(col[now]&&col[now]!=col[x]) ans++;
  14.             dfs(now);
  15.         }
  16.     }
  17. }
  18. void work(int &x,int &y){  //启发式合并
  19.     if(num[x].size()>num[y].size()) swap(x,y); //保证颜色x的节点个数少
  20.     for(int i=0;i<num[x].size();i++){ //颜色为x的每个节点now
  21.         int now=num[x][i];
  22.         for(int j=0;j<v[now].size();j++){ //与节点now相邻的每个节点t
  23.             int t=v[now][j];
  24.             if(col[t]&&col[t]!=x) ans--; //节点t的颜色与x不同,从答案中减去
  25.         }
  26.     }
  27.     for(int i=0;i<num[x].size();i++){ //合并
  28.         int now=num[x][i];
  29.         col[now]=y;
  30.         num[y].push_back(now);
  31.     }
  32.     for(int i=0;i<num[x].size();i++){
  33.         int now=num[x][i];
  34.         for(int j=0;j<v[now].size();j++){
  35.             int t=v[now][j];
  36.             if(col[t]&&col[t]!=y) ans++;
  37.         }
  38.     }
  39.     num[x].clear();
  40.     x=-1;
  41. }
  42. int main(){
  43.     int n,m,x,y;
  44.     cin>>n>>m;
  45.     for(int i=1;i<=n;i++) cin>>col[i],fa[i]=i;
  46.     for(int i=1;i<n;i++){
  47.         cin>>x>>y;
  48.         v[x].push_back(y);
  49.         v[y].push_back(x);
  50.     }
  51.     if(col[1]==0) ans=0;
  52.     else ans=1;
  53.     dfs(1);
  54.     for(int i=1;i<=m;i++){
  55.         cin>>x>>y; //把颜色x改成y
  56.         if(fa[y]==-1) fa[x]=-1,fa[y]=x;
  57.         else if(fa[x]!=-1&&fa[x]!=fa[y]) work(fa[x],fa[y]); //并查集,合并两个集合
  58.         cout<<ans<<endl;
  59.     }
  60.     return 0;
  61. }

未完待续...

orzzzzzzzzzzz我太菜了

小A的模拟军团——启发式合并

标签:总数   输入   tor   形式   c++   str   其他   输入格式   颜色不同   

原文地址:https://www.cnblogs.com/Pride205/p/10498590.html

(2)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!