编程之美2015初赛第一场 hihoCoder #1156 : 彩色的树(染色问题)
2015-08-17 20:27
381 查看
#1156 : 彩色的树
时间限制:2000ms 单点时限:1000ms 内存限制:256MB
描述
给定一棵n个节点的树,节点编号为1, 2, …, n。树中有n - 1条边,任意两个节点间恰好有一条路径。这是一棵彩色的树,每个节点恰好可以染一种颜色。初始时,所有节点的颜色都为0。现在需要实现两种操作: 1. 改变节点x的颜色为y; 2. 询问整棵树被划分成了多少棵颜色相同的子树。即每棵子树内的节点颜色都相同,而相邻子树的颜色不同。
输入
第一行一个整数T,表示数据组数,以下是T组数据。 每组数据第一行是n,表示树的节点个数。接下来n - 1行每行两个数i和j,表示节点i和j间有一条边。接下来是一个数q,表示操作数。之后q行,每行表示以下两种操作之一: 1. 若为"1",则询问划分的子树个数。 2. 若为"2 x y",则将节点x的颜色改为y。
输出
每组数据的第一行为"Case #X:",X为测试数据编号,从1开始。 接下来的每一行,对于每一个询问,输出一个整数,为划分成的子树个数。
数据范围
1 ≤ T ≤ 20 0 ≤ y ≤ 100000
小数据
1 ≤ n, q ≤ 5000
大数据
1 ≤ n, q ≤ 100000
样例输入
2 3 1 2 2 3 3 1 2 2 1 1 5 1 2 2 3 2 4 2 5 4 1 2 2 1 2 3 2 1
样例输出
Case #1: 1 3 Case #2: 1 5
解题步骤:1、求出所有点的父结点,这边用的bfs遍历
2、使用一个map<int,int>mp
,mp[i][j]=k表示第i个结点的颜色是j,并且和它同颜色的儿子结点数为k
3、ans开始只有1
4、color数组初始化为0
5、如果要更新颜色,求出变化的子树数量,更新ans
6、至于子树数量的变化,如x的颜色变为y,那么先求出x颜色没变化时的子结点ans0,再求出颜色变化后的子结点ans1,然后ans=ans+ans0-ans1,更新ans
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<map> #include<algorithm> #include<queue> using namespace std; #define N 100006 int n; vector<int> edge ;//保存边 int fa ;//记录父节点 map<int,int>mp ;//mp[i][j]=k表示第i个结点的颜色是j,并且和它同颜色的儿子结点数为k int color ;//color用来记录结点的颜色,初始化为0 void bfs() { queue<int> q; q.push(1); fa[1]=0; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<edge[u].size();i++) { int v=edge[u][i]; if(fa[v]!=-1) continue; fa[v]=u; q.push(v); } } } int main() { int t; scanf("%d",&t); int ac=0; while(t--) { printf("Case #%d:\n",++ac); for(int i=0;i<N;i++)edge[i].clear(); memset(fa,-1,sizeof(fa)); scanf("%d",&n); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); edge[u].push_back(v); edge[v].push_back(u); } bfs();//bfs用来求所有的点的父节点,待会要用到 for(int i=1;i<=n;i++) { mp[i].clear(); color[i]=0; if(i==1) mp[i][0]=edge[i].size(); else mp[i][0]=edge[i].size()-1;//这边减掉1的原因是i肯定要和1这个根结点相连,所以减1 } //for(int i=1;i<=n;i++) //printf("--%d\n",mp[i][0]); int q; scanf("%d",&q); int ans=1; while(q--) { int c; scanf("%d",&c); if(c==1) printf("%d\n",ans);//如果是1就输出结果,开始只有一棵 else { int x,y; scanf("%d%d",&x,&y); int ans0=mp[x][color[x]];//ans0表示还未变色时x的子结点总数 if(x!=1 && color[fa[x]]==color[x]) ans0++;//如果不是根结点,并且x的父结点和它颜色相同,则++ int ans1=mp[x][y];//ans1表示x变完颜色后的子结点个数 if(x!=1 && color[fa[x]]==y) ans1++;//如果不是根结点,并且x的父结点和它颜色相同,则++ ans=ans+ans0-ans1;//ans加上增加的子树 if(x!=1) { mp[fa[x]][color[x]]--;//因为要变色,所以父结点的子结点 -1 color[x]=y;//将颜色改变 mp[fa[x]][color[x]]++;//当前颜色的子结点 +1 } color[x]=y;//如果是根节点的话, } } } return 0; }
View Code
相关文章推荐
- PHP获取Cookie模拟登录CURL
- MyEclipse 快捷键
- [JavaWeb基础] 011.Struts2 配置拦截器
- *怎么使用Delphi获取当前的时间,精确到毫秒
- (C++ 11) 泛型算法(一)
- TextView 代码加载上下左右drawable
- 黑马程序员-[OC语言] 第三篇:MRC手动内存管理总结
- HashMap和HashSet的区别
- C++ Read a whole File using ifstream
- php笔记
- Java解析XML
- 黑马程序员-[OC语言] 第二篇:继承、多态概述
- Python的函数参数
- java环境配置
- eclipse-hadoop插件
- java枚举基础及使用
- A*寻路算法lua实现
- 搜芽 vbeta-1.3.1 安卓版
- ASP.NET网站与ASP.NET应用程序的区别
- 软件测试之独步武林系列(一)