标签:总数 输入 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
保证输入数据合法
- #include<bits/stdc++.h>
- using namespace std;
- vector<int> v[200005],num[200005];
- int ans,col[200005],fa[200005];
- bool vis[200005];
- void dfs(int x){
- vis[x]=true; //标记当前节点已访问
- num[col[x]].push_back(x); //把颜色相同的节点放入一个数组中
- for(int i=0;i<v[x].size();i++){ //与x相邻的所有节点now
- int now=v[x][i];
- if(!vis[now]){ //如果now没有访问过
- //如果一个节点和他父节点颜色不同,答案就++
- if(col[now]&&col[now]!=col[x]) ans++;
- dfs(now);
- }
- }
- }
- void work(int &x,int &y){ //启发式合并
- if(num[x].size()>num[y].size()) swap(x,y); //保证颜色x的节点个数少
- for(int i=0;i<num[x].size();i++){ //颜色为x的每个节点now
- int now=num[x][i];
- for(int j=0;j<v[now].size();j++){ //与节点now相邻的每个节点t
- int t=v[now][j];
- if(col[t]&&col[t]!=x) ans--; //节点t的颜色与x不同,从答案中减去
- }
- }
- for(int i=0;i<num[x].size();i++){ //合并
- int now=num[x][i];
- col[now]=y;
- num[y].push_back(now);
- }
- for(int i=0;i<num[x].size();i++){
- int now=num[x][i];
- for(int j=0;j<v[now].size();j++){
- int t=v[now][j];
- if(col[t]&&col[t]!=y) ans++;
- }
- }
- num[x].clear();
- x=-1;
- }
- int main(){
- int n,m,x,y;
- cin>>n>>m;
- for(int i=1;i<=n;i++) cin>>col[i],fa[i]=i;
- for(int i=1;i<n;i++){
- cin>>x>>y;
- v[x].push_back(y);
- v[y].push_back(x);
- }
- if(col[1]==0) ans=0;
- else ans=1;
- dfs(1);
- for(int i=1;i<=m;i++){
- cin>>x>>y; //把颜色x改成y
- if(fa[y]==-1) fa[x]=-1,fa[y]=x;
- else if(fa[x]!=-1&&fa[x]!=fa[y]) work(fa[x],fa[y]); //并查集,合并两个集合
- cout<<ans<<endl;
- }
- return 0;
- }
未完待续...
orzzzzzzzzzzz我太菜了
小A的模拟军团——启发式合并
标签:总数 输入 tor 形式 c++ str 其他 输入格式 颜色不同
原文地址:https://www.cnblogs.com/Pride205/p/10498590.html