Rainbow Roads(dfs序+树上差分)

17 篇文章 0 订阅
4 篇文章 0 订阅

题目链接,D题
题意: 给出一颗树,树上每条边都有一个颜色,定义如果以这个点为端点的所有简单路径都没有相邻的两条边颜色相同时,这个点为good点,求 g o o d good good点的数量以及是哪个点。
思路:
假设节点u和节点v均与节点w相邻,且e(w,u)与e(w,v)颜色相同,那么要分两种情况:

  1. u u u v v v均是w的子树,则这两个点的子树上所有的点包括这两个点都不是 g o o d good good点。
  2. u u u w w w的父节点, v v v w w w的子节点,则u的外子树和u的内子树除 w w w拿部分外的节点都不是 g o o d good good点。如下图:
    在这里插入图片描述
    于是可以用 d f s dfs dfs序来做, d f s dfs dfs序感觉考的很少,但在这道题里有大用, [ s t [ u ] , e n [ u ] ] [st[u],en[u]] [st[u],en[u]]的所有点就构成了u的子树,可以用差分的思想,给 s t [ u ] , e n [ u ] st[u],en[u] st[u],en[u]打上标记,最后再求前缀和。
#include<bits/stdc++.h>
#define ll unsigned long long
using namespace std;
const int N = 1e5 + 10;
int n, h[N], cnt, st[N], en[N], dfn, pre[N], s[N], ans;
pair<int, int> p[N];
struct node {
    int v, w, nt;
} no[N];
void add(int u, int v, int w) {
    no[cnt] = node{v, w, h[u]};
    h[u] = cnt++;
}
void dfs(int u, int fa) {
    st[u] = ++dfn;
    pre[u] = fa;
    for(int i = h[u]; ~i; i = no[i].nt) {
        int v = no[i].v;
        if(v != fa)
            dfs(v, u);
    }
    en[u] = dfn;
}
int main() {
    memset(h, -1, sizeof h);
    scanf("%d", &n);
    for(int u, v, w, i = 1; i < n; i++) {
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w), add(v, u, w);
    }
    dfs(1, 0);
    for(int i = 1; i <= n; i++) {
        int num = 0, k;
        for(int j = h[i]; ~j; j = no[j].nt)
            p[num++] = make_pair(no[j].w, no[j].v);
        sort(p, p + num);
        for(int j = 0; j < num; j = k) {
            for(k = j; p[k].first == p[j].first && k < num; k++);
            if(k > j + 1)
                for(int x = j; x < k; x++) {
                    int v = p[x].second;
                    if(v == pre[i])//第一种情况
                        s[1]++, s[st[i]]--, s[en[i] + 1]++;
                    else//第二种情况
                        s[st[v]]++, s[en[v] + 1]--;
                }
        }
    }
    for(int i = 1; i <= n; i++)
        s[i] += s[i - 1];
    for(int i = 1; i <= n; i++)
        if(!s[st[i]])
            ans++;
    printf("%d\n", ans);
    for(int i = 1; i <= n; i++)
        if(!s[st[i]])
            printf("%d\n", i);
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值