Codeforces 1467E. Distinctive Roots in a Tree(树上差分)

58 篇文章 0 订阅
35 篇文章 1 订阅

Codeforces Round #695 (Div. 2) 全文见:https://blog.csdn.net/qq_43461168/article/details/112598001

E. Distinctive Roots in a Tree

题意:输出符合条件的点的个数。条件:从这个点出发到任意一个点的路径中没有重复的值。

思路参考:https://blog.csdn.net/forever_shi/article/details/112467674

思路:反过来想。 题目要求符合条件的点的个数。 但是枚举每个点是否合法显然不合理。 但是判断一个点不合法比较简单。所以可以标记所有的不合法点。剩下的就是答案了。怎么标记呢。 假设当前点为pos,a[pos] 为 x 。考虑两种情况。

1. pos 的后代(某个子树中的某个节点) y == x。 那么除了 dfs序位于[pos - y] 之间的点。其他的点一定是不合法的。其他的点必然会经过这两个 x 的。显然不合法。所以要标记除这条路径上的所有点。 用到树上差分。利用dfs序可以很方便的找出 dfn[pos] - dfn[y] 的所有点。
2. 除了子树和自己以外。 还存在x,那么pos的所有子树都不合法。因为这说明,连接父亲的那条边过去,还会碰到一个x。那么如果以pos 的子节点为根。必然会经过pos 和 另一个x。 所以,同样用差分把pos所有子树打上标记。

还有一个小问题就是,数值比较大,可以开map计数。也可以离散化之后计数。 离散化比map快一些。

AC代码:

#include <iostream>
#include <bits/stdc++.h>
#define int long long
#define mk make_pair
#define gcd __gcd
using namespace std;
const double eps = 1e-10;
const int mod = 1e9+7;
const int N = 3e5+7;
int n,m,k,t = 1,cas = 1;
int a[N],b[N];
int cnt[N];     // 计数
int vis[N];     // 计数
int in[N];      // dfs 进入序号
int out[N];     // dfs 退出序号
int sum[N];     // 差分数组
vector<int> edge[N];
vector<int> values;
int tot = 0;

void dfs(int pos,int fa){
    in[pos] = ++tot;
    int cntt = vis[a[pos]] ++;
    for(int i = 0 ; i < edge[pos].size() ; i ++){
        int to = edge[pos][i];
        if(to == fa) continue;
        int now = vis[a[pos]];
        dfs(to,pos);
        if(vis[a[pos]] > now){
            sum[1] ++;
            sum[n+1] ++;
            sum[in[to]] --;
            sum[out[to]+1] ++;
        }
    }
    out[pos] = tot;
    if(vis[a[pos]] - cntt != cnt[a[pos]]){
        sum[in[pos]] ++;
        sum[out[pos]+1] --;
    }
}

signed main(){
    cin>>n;
    for(int i = 1 ; i <= n  ; i ++){
        cin>>a[i];
        values.push_back(a[i]);
    }
    for(int i = 0 ; i < n-1 ; i ++){
        int x,y;
        cin>>x>>y;
        edge[x].push_back(y);
        edge[y].push_back(x);
    }
    sort(values.begin(),values.end());
    values.erase(unique(values.begin(),values.end()),values.end());
    for(int i = 1 ; i <= n ; i ++){
        a[i] = lower_bound(values.begin(),values.end(),a[i])-values.begin();
        cnt[a[i]] ++;
    }
    dfs(1,-1);
    int ans = 0;
    for(int i = 1; i <= n ; i ++){
        sum[i] += sum[i-1];
        if(sum[i] == 0){
            ans ++;
        }
    }
    cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用的内容,CodeForces的初始分由1500改为了1400,并且前六场的初始分配如下:第一场500分,第二场350分,第三场250分,第四场150分,第五场100分,第六场50分。所以,根据你在第一场的表现分为368,你的总分应为868(1400+368)。接下来的五场比赛,你的表现分将根据具体情况来决定。每场比赛的表现分会对你的总分产生影响。 关于其他引用和的代码,它们似乎是一些针对不同情况进行计算和输出的算法,并不直接涉及到CodeForces上的分数计算。所以,如果你有关于CodeForces上分的具体问题,请提供更多详细信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [CodeForces前六场定级赛赋分规则(2020.5修订)及各段位对应分数段](https://blog.csdn.net/Sunshine_xiaohao/article/details/112106625)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [CodeForces上分日记 (思维题)(A. Garland)1809A (Educational Round 145 For Div.2)](https://blog.csdn.net/weixin_60375636/article/details/130243342)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [【codeforces】一切为了上分:骚操作合集](https://blog.csdn.net/weixin_45497996/article/details/109157711)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值