[2015编程之美] 第一场A

#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

TLE代码,能过小数据。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define ll long long
#define N 100010

struct Edge
{
    int to,next;
}edge[N];
int tot;
int col[N];
int head[N];
int n,m;
int ans;

void init()
{
    tot=0;
    ans=1;
    for(int i=1;i<=n;i++) col[i]=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void update(int u,int c)
{
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(col[v]!=col[u] && col[v]==c) ans--;
        else if(col[v]==col[u] && col[v]!=c) ans++;
    }
    col[u]=c;
}
int main()
{
    int T,iCase=1;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        printf("Case #%d:\n",iCase++);
        scanf("%d",&m);
        while(m--)
        {
            int op,pos,c;
            scanf("%d",&op);
            if(op==1) printf("%d\n",ans);
            else
            {
                scanf("%d%d",&pos,&c);
                update(pos,c);
            }
        }
    }
    return 0;
}

正解代码:

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;
#define ll long long
#define N 100010

struct Edge
{
    int to,next;
}edge[N<<1];

int n,m;
int ans;
int tot;
int fa[N];
int vis[N];
int col[N];
int head[N];
map<int,int> mp[N];

void init()
{
    tot=0;
    ans=1;
    for(int i=1;i<=n;i++)
    {
        col[i]=0;
        mp[i].clear();
    }
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!vis[v])
        {
            fa[v]=u;
            mp[u][0]++;
            dfs(v);
        }
    }
}
void update(int x,int c)
{
    if(col[x]==c) return;
    int y=fa[x];
    //对儿子节点
    ans+=mp[x][col[x]];
    ans-=mp[x][c];
    //对父亲节点
    if(y!=-1)
    {
        if(c!=col[y]) ans++;
        if(col[x]!=col[y]) ans--;
        mp[y][col[x]]--;
        mp[y][c]++;
    }
    col[x]=c;
}
int main()
{
    int T,iCase=1;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        fa[1]=-1;
        dfs(1);
        printf("Case #%d:\n",iCase++);
        scanf("%d",&m);
        while(m--)
        {
            int op,pos,c;
            scanf("%d",&op);
            if(op==1) printf("d\n",ans);
            else
            {
                scanf("%d%d",&pos,&c);
                update(pos,c);
            }
        }
    }
    return 0;
}

时间: 2024-10-14 19:42:57

[2015编程之美] 第一场A的相关文章

[2015编程之美] 第一场C

题目3 : 质数相关 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为

计蒜之道2015程序设计大赛初赛第一场——搜狗输入法的分词算法

(一)题面 计蒜之道2015程序设计大赛初赛第一场——搜狗输入法的分词算法 搜狗输入法最近的用户输入中出现了一种新的输入模式,形如 “0k1234567”,搜狗的工程师发现这一模式后了解到,这是一种新被提出的对于十五进制数字的标记模式,其中 “0k” 是标记进制为15的前缀标记,之后的部分 “1234567” 是实际的十五进制的数字串. 在发现这一标记模式后,搜狗的工程师开始尝试在已有的分词算法上进一步加入对于十五进制数字串的处理,把网页上的这种形式的 15 进制数正确地提取出来.我们知道,标记

HDU 4508 湫湫系列故事——减肥记I (2013腾讯编程马拉松初赛第一场)

http://acm.hdu.edu.cn/showproblem.php?pid=4508 题目大意: 给定一些数据. 每组数据以一个整数n开始,表示每天的食物清单有n种食物. 接下来n行,每行两个整数a和b,其中a表示这种食物可以带给湫湫的幸福值(数值越大,越幸福),b表示湫湫吃这种食物会吸收的卡路里量. 最后是一个整数m,表示湫湫一天吸收的卡路里不能超过m. 思路: 完全背包. 一开始以为是01背包. 敲了01后样例2不对啊!!! 然后改成完全就过了..就改循环体就好了.. #includ

hdu 5288||2015多校联合第一场1001题

http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a array A of size n ,defined a function f(l,r) represent the number of i (l<=i<=r) , that there's no j(l<=j<=r,j<>i) satisfy ai mod aj=0,now OO want to know ∑i

hdu5289||2015多校联合第一场1002贪心+RMQ

http://acm.hdu.edu.cn/showproblem.php?pid=5289 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to

编程之美第一题 超级赛亚ACMer

题意太麻烦 , 就不说了, 编美第一题,  也算是签到题,和队友一起果断混了5个水 题, 也不知道会不会有小熊公仔,废话不多说,细说比赛我出的三个水题. 题解: 这个人每次战斗力会跨越,  YY了一下,每次跨越的落脚点为该跨越距离中最后一个点, 然后就A了 ,  YY 大法好. 代码: #include<stdio.h> #include<iostream> #include<algorithm> using namespace std; int n, m, k; __

2015编程之美初赛第一场 A 彩色的树

时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定一棵n个节点的树,节点编号为1, 2, -, n.树中有n - 1条边,任意两个节点间恰好有一条路径.这是一棵彩色的树,每个节点恰好可以染一种颜色.初始时,所有节点的颜色都为0.现在需要实现两种操作: 1. 改变节点x的颜色为y: 2. 询问整棵树被划分成了多少棵颜色相同的子树.即每棵子树内的节点颜色都相同,而相邻子树的颜色不同. 输入 第一行一个整数T,表示数据组数,以下是T组数据. 每组数据第一行是n,表示树的节

2015编程之美初赛第一场 B 建造金字塔

 时间限制:4000ms 单点时限:2000ms 内存限制:256MB 描述 在二次元中,金字塔是一个底边在x轴上的等腰直角三角形. 你是二次元世界的一个建筑承包商.现在有N个建造订单,每个订单有一个收益w,即建造此金字塔可获得w的收益.对每个订单可以选择建造或不建造. 建造一个金字塔的成本是金字塔的面积,如果两个或多个金字塔有重叠面积,则建造这些金字塔时重叠部份仅需建造一次. 建造一组金字塔的总利润是收益总和扣除成本.现给出这些订单,请求出最大利润. 输入 输入数据第一行为一个整数T,表示

2015编程之美初赛第一场 C 质数相关

 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数.一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关.如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关.现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小. 输入 第一行为一个数T,为数据组数.之后每组数据包含两行. 第一行为N,为集合S的大小.第二行为N个整数,表示集