树上启发式合并

补题时碰见的骚操作。可以在nlogn的时间内处理一些没有修改的,对子树的查询问题。

具体方法为

1.轻重链剖分,找出重儿子。(预处理)

2.先处理轻儿子,不记录 贡献。

3.处理重儿子,记录贡献。

4.将当前节点和轻儿子的贡献和重儿子合并。

5.如果当前节点是轻儿子的话,消除影响。

 

算法的正确性很容易理解。重儿子不用清空了, 因为我的兄弟节点都已经处理完了,我不会影响到兄弟节点。

时间复杂度不会证明。

hdu 4358

题目大意:询问每个节点颜色出现次数为k的颜色有多少个。

解题思路:由于对子树只有查询没有修改,可以dfs序+莫队。当时。。树上启发式合并更无脑,更快。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define sca(x) scanf("%d",&x)
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define N 100005

vector<int>G[N];
int sz[N],son[N];
int cnt[N],a[N],ou[N];
int b[N];
int Son,sum;
int n,k;

void dfs1(int u,int fa)
{
    sz[u]=1;
    int mx=-1;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v!=fa)
        {
            dfs1(v,u);
            sz[u]+=sz[v];
            if(sz[v]>mx)mx=sz[v],son[u]=v;
        }
    }
}

void add(int u,int fa,int val)
{
    if(cnt[a[u]]==k)sum--;
    cnt[a[u]]+=val;
    if(cnt[a[u]]==k)sum++;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==fa||v==Son)continue;
        add(v,u,val);
    }
}

void dfs(int u,int fa,int f)
{
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i];
        if(v==fa||v==son[u])continue;
        dfs(v,u,0);
    }
    if(son[u])dfs(son[u],u,1),Son=son[u];
    add(u,fa,1);
    ou[u]=sum;
    if(son[u])Son=0;
    if(!f)add(u,fa,-1),sum=0;
}

int main()
{
    int t;
    sca(t);
    for(int cas=1; cas<=t; cas++)
    {
        sca(n),sca(k);
        memset(son,0,sizeof(son));
        sum=0,Son=0;
        rep(i,1,n)G[i].clear();
        rep(i,1,n)sca(a[i]),b[i]=a[i];
        sort(b+1,b+1+n);
        int len=unique(b+1,b+1+n)-b-1;
        rep(i,1,n)a[i]=lower_bound(b+1,b+1+len,a[i])-b;
        rep(i,1,n-1)
        {
            int x,y;
            sca(x),sca(y);
            G[x].pb(y);
            G[y].pb(x);
        }
        dfs1(1,-1);
        dfs(1,-1,0);
        int q;
        sca(q);
        printf("Case #%d:\n",cas);
        while(q--)
        {
            int tmp;
            sca(tmp);
            printf("%d\n",ou[tmp]);
        }
        if(cas!=t)printf("\n");
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
决策树是一种常用的机器学习算法,可以用于分类和回归问题。它通过分支结构逐步地对数据进行划分,最终得到一个树型模型。 然而,决策树在构建过程中容易出现过度拟合的问题。过度拟合是指模型过多地学习了训练样本的细节和噪声,导致在新的未知数据上表现不佳。 导致决策树过度拟合的主要原因有以下几个方面: 1. 样本数量较少:当训练样本数量较少时,决策树容易过度拟合,因为它可以完全记住每个样本的特征和标签。 2. 样本噪声:如果训练样本中存在噪声,决策树会试图将这些噪声也纳入考虑,导致模型的泛化能力下降。 3. 决策树的深度:决策树的深度决定了模型的复杂度。当决策树过深时,模型会越来越复杂且过度拟合的风险增加。 为了解决决策树过度拟合的问题,可以采取以下措施: 1. 剪枝:通过减少树的深度或合并决策节点来降低模型的复杂度,从而避免过度拟合。剪枝通常基于模型的性能指标,如交叉验证误差。 2. 增加样本数量:增加训练样本数量可以提高模型的泛化能力。更多的样本可以帮助决策树更好地捕捉数据集的整体特征。 3. 特征选择:选择合适的特征子集可以减少模型的复杂度,并提高对关键特征的关注程度。可以使用启发式算法或信息增益等指标来选择重要的特征。 4. 随机森林:随机森林是一种基于决策树的集成学习方法,通过组合多个决策树来减少过度拟合的风险。随机森林可以通过随机选择特征和样本子集来构建多个决策树,并通过投票或平均来进行预测。 以上是关于决策树过度拟合问题的回答,希望能够对您有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值