2809: [Apio2012]dispatching 启发式合并treap 可并堆

本文详细介绍了如何利用Treap数据结构解决启发式合并问题,通过从底向上计算子树的前k个小于等于M的元素,并在合并过程中更新答案。尽管常数较大,但最终成功通过案例。同时,对比了可并堆的实现,指出其效率受限于无效节点合并的问题。

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

我曾写过N次启发式合并splay。。由于太弱从来没调出来过。。
这次写了一发treap终于过啦!(然而常数太大被可并堆虐成狗了)


首先,作法显然,从底向上,每次计算子树的前k小数保证和<=M,然后将两棵子树合并,更新答案。
显然treap和可并堆都是支持这些操作的。不过treap合并的时候有很多无效的节点一直在合并,如果能split的话应该能快一些吧(然而我不会)。

treap:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define N 100005
#define ll long long 
using namespace std;
int n,cnt,tmp;
ll ans,M;
int next[N<<1],list[N<<1];
int head[N],f[N],size[N],root[N],rnd[N],ls[N],rs[N];
ll sum[N],val[N],c[N],l[N];
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
inline void addedge(int x,int y)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
}
int find(int i)
{
    return f[i]==i?i:f[i]=find(f[i]);
}
inline void pushup(int k)
{
    size[k]=size[ls[k]]+size[rs[k]]+1;
    sum[k]=sum[ls[k]]+sum[rs[k]]+val[k];
}
inline void lturn(int &k)
{
    int t=rs[k]; rs[k]=ls[t]; ls[t]=k; pushup(k); pushup(t); k=t;
}
inline void rturn(int &k)
{
    int t=ls[k]; ls[k]=rs[t]; rs[t]=k; pushup(k); pushup(t); k=t;
}
void insert(int &k,ll x,int y)
{
    if (!k)
    {
        k=y;
        size[k]=1;
        sum[k]=x;
        val[k]=x;
        rnd[k]=rand();
        return;
    }
    size[k]++; sum[k]+=x;
    if (x<=val[k]) 
    {
        insert(ls[k],x,y);
        if (rnd[ls[k]]>rnd[k]) rturn(k);
    }
    else
    {
        insert(rs[k],x,y);
        if (rnd[rs[k]]>rnd[k]) lturn(k);
    }
}
void merge(int x,int &y)
{
    if (!x) return;
    merge(ls[x],y);
    merge(rs[x],y);
    ls[x]=rs[x]=0;
    insert(y,c[x],x);
}
void find_max(int k,ll MAXN)
{
    if (!k) return;
    if (sum[ls[k]]+val[k]<=MAXN) tmp+=size[ls[k]]+1,find_max(rs[k],MAXN-sum[ls[k]]-val[k]);
    else if (sum[ls[k]]<=MAXN) {tmp+=size[ls[k]]; return;}
    else find_max(ls[k],MAXN);
}
void dfs(int x)
{
    if (!head[x]) {ans=max(ans,l[x]); return;}
    for (int i=head[x];i;i=next[i]) dfs(list[i]);
    for (int i=head[x];i;i=next[i])
    {
        int p=find(x),q=find(list[i]);
        if (size[root[p]]>size[root[q]]) swap(p,q);
        merge(root[p],root[q]); f[p]=q;
    }
    int p=find(x);
    tmp=0;
    find_max(root[p],M);
    ans=max(ans,tmp*l[x]);
}
int main()
{
    n=read(); M=read();
    for (int i=1;i<=n;i++) f[i]=i;
    for (int i=1;i<=n;i++)
    {
        int x=read(); c[i]=read(); l[i]=read();
        if (x) addedge(x,i); 
        insert(root[i],c[i],i);
    }
    dfs(1);
    cout << ans << endl;
    return 0;
}

可并堆:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define N 100005
#define ll long long 
using namespace std;
int n,cnt;
ll M,ans;
ll l[N],c[N],sum[N];
int ls[N],rs[N],d[N],root[N],head[N],next[N],list[N],size[N];
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
inline void insert(int x,int y)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
}
int merge(int x,int y)
{
    if (!x||!y) return x+y;
    if (c[x]<c[y]) swap(x,y);
    sum[x]+=sum[y];
    size[x]+=size[y];
    rs[x]=merge(rs[x],y);
    if (d[rs[x]]>d[ls[x]]) swap(ls[x],rs[x]);
    d[x]=d[rs[x]]+1;
    return x;
}
int main()
{
    n=read(); M=read();
    for (int i=1;i<=n;i++)
    {
        int x=read(); c[i]=read(); l[i]=read();
        if (x) insert(x,i); root[i]=i; sum[i]=c[i]; size[i]=1;
    }
    for (int x=n;x;x--)
    {
        for (int i=head[x];i;i=next[i])
            root[x]=merge(root[x],root[list[i]]);
        while (sum[root[x]]>M) root[x]=merge(ls[root[x]],rs[root[x]]);
        ans=max(ans,size[root[x]]*l[x]);

    }
    cout << ans << endl;
    return 0;
}   
资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值