Educational Codeforces Round 2 E. Lomsat gelral(level 3)(dsu on tree)

本文深入探讨了树上启发式合并(dsu on tree)算法,一种解决树形结构中子树问题的有效方法。文章详细解析了算法原理,通过具体实例展示了如何利用该算法求解节点颜色支配问题,同时提供了代码实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题意:

给你一颗树,每一个节点有一个颜色,在节点v的子树中,颜色x出现的次数最多,则称x支配v的子树,注意一颗子树可能被多个颜色支配,让你输出对于每一个节点,支配他的子树的颜色的编号和

 

解析:

code force上大佬的讲解——dsu on tree

树上启发式合并的模板题

总结一下,对于在做节点x的子树问题时,答案是通过x的重孩子继承过来,然后在遍历x的每一个轻孩子,

来更新答案,使得其变成x的子树问题的答案

状态量取决于他的孩子节点时,如果状态量是一个变量,那么直接从他的重孩子继承

,再遍历轻孩子时更新。对于一维的状态数组,则用STL的二维指针来做,状态数组先指向重孩子的状态数组,

之后在遍历轻孩子时考虑重新申请空间还是在原有重孩子的状态数组上更新

 

对于这道题,我做烦了...其实不需要set<int> *vis[maxn]这个状态数组的。

因为如果在更新轻孩子时(此时重孩子以遍历过),出现更大的颜色,那么直接重新开始计数

如果没有出现更大的颜色(可能出现与最大值相等的颜色),那么直接将这个颜色加到ans中就好了,

因为这个颜色在重孩子中一定是<最大值的,所以没有被加入到答案过

我的代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9+7;

const int maxn = 1e5+10;

int res[maxn];
ll sum[maxn];
set<int> *vis[maxn];

int col[maxn];
vector<int> g[maxn];
int sz[maxn],st[maxn];
int ver[maxn];
void getsz(int v, int p,int& tim){
    sz[v] = 1;  // every vertex has itself in its subtree
    ver[tim] = v;
    st[v]=tim;
    for(auto u : g[v])
        if(u != p){
            ++tim;
            getsz(u, v, tim);
            sz[v] += sz[u]; // add size of child u to its parent(v)
        }
}

int cnt[maxn];
void dfs(int v, int p, bool keep){
    int mx = -1, bigChild = -1;
    for(auto u : g[v])
       if(u != p && sz[u] > mx)
          mx = sz[u], bigChild = u;
    for(auto u : g[v])
        if(u != p && u != bigChild)
            dfs(u, v, 0);  // run a dfs on small childs and clear them from cnt
    if(bigChild != -1)
        dfs(bigChild, v, 1),res[v]=res[bigChild],sum[v]=sum[bigChild],vis[v]=vis[bigChild];  // bigChild marked as big and not cleared from cnt
    else
        res[v]=sum[v]=0,vis[v]=new set<int>();

    for(auto u : g[v])
	if(u != p && u != bigChild)
	    for(int p = st[u]; p < st[u]+sz[u]; p++)
		cnt[ col[ ver[p] ] ]++,res[v]=max(res[v],cnt[ col[ ver[p] ] ]);
    cnt[ col[v] ]++,res[v]=max(res[v],cnt[ col[v] ]);

    if(bigChild != -1&&res[v]>res[bigChild])
    {
        vis[v]=new set<int>();
        sum[v]=0;
    }

    for(auto u : g[v])
	if(u != p && u != bigChild)
	    for(int p = st[u]; p < st[u]+sz[u]; p++)
            if(cnt[col[ver[p]]]==res[v]&&!(*vis[v]).count(col[ver[p]])) sum[v]+=col[ver[p]],(*vis[v]).insert(col[ver[p]]);

    if(cnt[col[v]]==res[v]&&!(*vis[v]).count(col[v])) sum[v]+=col[v],(*vis[v]).insert(col[v]);


    //now cnt[c] is the number of vertices in subtree of vertex v that has color c. You can answer the queries easily.
    if(keep == 0)
        for(int p = st[v]; p < st[v]+sz[v]; p++)
            cnt[ col[ ver[p] ] ]--;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&col[i]);
    }

    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    int tim=1;
    getsz(1,0,tim);
    dfs(1,0,1);
    for(int i=1;i<=n;i++) printf("%lld ",sum[i]);


}

 

大佬的代码(优化了我上面说的那个情况)

 

//God & me // ya mahdi adrekni 
//@Shayan_Cheshmjahan: Oh my friend, congratulations!
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn=1e5+12;
int n,col[maxn],sz[maxn],maxx,cnt[maxn];
long long ans[maxn],can;
bool badboy[maxn];
vector<int>g[maxn];
void dastan(int v=0,int p=-1){
  sz[v]=1;
  for(auto &u:g[v])
    if(u!=p)dastan(u,v),sz[v]+=sz[u];
}
void reval(int x){
  if(maxx<++cnt[x])
    maxx=cnt[x],can=x;
  else if(maxx==cnt[x])
    can+=x;
}
void add(int v,int p=-1){
  reval(col[v]);
  for(auto &u:g[v])
    if(u!=p && !badboy[u])
      add(u,v);
}
void rem(int v,int p=-1){
  cnt[col[v]]--;
  for(auto &u:g[v])
    if(u!=p && !badboy[u])
      rem(u,v);
}
void dfs(int v=0,int p=-1,bool hrh=0){//HRH?! mipasandam!
  int mx=0,big=-1;
  for(auto &u:g[v])
    if(u!=p && sz[u]>mx)
      mx=sz[u],big=u;
  for(auto &u:g[v])
    if(u!=p && u!=big)
      dfs(u,v,1);
  if(big+1)
    dfs(big,v),badboy[big]=1;
  add(v,p);
  if(big+1)
    badboy[big]=0;
  ans[v]=can;
  if(hrh)
    rem(v,p),maxx=can=0;
}
main(){
  scanf("%d",&n);
  for_each(col,col+n,[](int &x){scanf("%d",&x);});
  for(int i=1,v,u;i<n;i++)scanf("%d%d",&v,&u),g[--v].pb(--u),g[u].pb(v);
  dastan(),dfs();
  for_each(ans,ans+n,[](long long &x){printf("%lld ",x);});putchar('\n');
  return 0;
}

 

### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置和速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线段交集判断和平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类和辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值