news 2025/12/29 19:45:21

左偏树作业总结

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
左偏树作业总结

左偏树

算法浅析

左偏树本质上是就是一个堆,不过在堆的基础上新增了 “左偏” 的性质,使得合并跟加快速.
思路上大致可以从 “合并" 的角度想起.

A - 可并堆 1

板题,直接上代码.

#include<bits/stdc++.h> # define Maxn 100005 using namespace std; bool bz[Maxn]; int n,m,op,x,y,v,tot; struct Node{int fa,dist,l,r,v;}tr[Maxn]; int find(int x) { if(x!=tr[x].fa) tr[x].fa=find(tr[x].fa); return tr[x].fa; } int Merge(int x,int y) { if((!x)||(!y)) return x+y; if(tr[x].v>tr[y].v) swap(x,y); tr[x].r=Merge(tr[x].r,y); if(tr[tr[x].l].dist<tr[tr[x].r].dist) swap(tr[x].l,tr[x].r); tr[x].dist=tr[tr[x].r].dist+1; return x; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&v); tr[++tot]={tot,0,0,0,v}; } while(m--) { scanf("%d",&op); if(op==1) { scanf("%d%d",&x,&y); if(bz[x]|bz[y]) continue; int f1=find(x),f2=find(y); if(f1==f2) continue; tr[f1].fa=tr[f2].fa=Merge(f1,f2); } if(op==2) { scanf("%d",&x); if(bz[x]) {printf("-1\n");continue;} int f1=find(x);bz[f1]=1; printf("%d\n",tr[f1].v); if((!tr[f1].l)&&(!tr[f1].r)) continue; tr[f1].fa=tr[tr[f1].l].fa=tr[tr[f1].r].fa=Merge(tr[f1].l,tr[f1].r); } } return 0; }

B - Monkey King

也是板题,不过要注意最后输出的是所有的最大。

#include<bits/stdc++.h> # define Maxn 100005 using namespace std; int n,m,v,x,y,tot,p[Maxn]; struct Node{int fa,l,r,dist,v,id;}tr[Maxn<<2]; int find(int x) { if(x!=tr[x].fa) tr[x].fa=find(tr[x].fa); return tr[x].fa; } int Merge(int x,int y) { if((!x)||(!y)) return x+y; if(tr[x].v<tr[y].v) swap(x,y); tr[x].r=Merge(tr[x].r,y); if(tr[tr[x].l].dist<tr[tr[x].r].dist) swap(tr[x].l,tr[x].r); tr[x].dist=tr[tr[x].r].dist+1; return x; } void clear() { for(int i=1;i<=tot;i++) tr[i]={0,0,0,0,0,0}; tot=0; } int main() { // freopen("my.out","w",stdout); while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) { scanf("%d",&v); tr[++tot]={i,0,0,0,v,i},p[i]=i; } scanf("%d",&m); while(m--) { scanf("%d%d",&x,&y); int f1=find(p[x]),f2=find(p[y]); if(f1==f2) {printf("-1\n");continue;} int newf1,newf2,Newf1,Newf2,RT; newf1=tr[f1].fa=tr[tr[f1].l].fa=tr[tr[f1].r].fa=Merge(tr[f1].l,tr[f1].r); tr[++tot]={tot,0,0,0,tr[f1].v/2,tr[f1].id},p[tr[f1].id]=tot; Newf1=tr[tot].fa=tr[newf1].fa=Merge(tot,newf1); newf2=tr[f2].fa=tr[tr[f2].l].fa=tr[tr[f2].r].fa=Merge(tr[f2].l,tr[f2].r); tr[++tot]={tot,0,0,0,tr[f2].v/2,tr[f2].id},p[tr[f2].id]=tot; Newf2=tr[tot].fa=tr[newf2].fa=Merge(tot,newf2); RT=tr[Newf1].fa=tr[Newf2].fa=Merge(Newf1,Newf2); printf("%d\n",tr[RT].v); }clear(); } return 0; }

C - 派遣

显然在领导固定时,人越多越好,于是考虑从小到大依次选择,然后删掉多余的.
显然可用左偏树实现. 每个点最多进堆一次,出堆一次,时间复杂度O(nlogn)O(nlogn)O(nlogn).

#include<bits/stdc++.h> # define Maxn 100005 # define ll long long using namespace std; int n,m,srt[Maxn],RT,cnt; int head[Maxn],tot=1; ll ans; struct Edge{int to,next;}e[Maxn]; struct Node{int fa,c,l;}a[Maxn]; struct Tree{int fa,l,r,dist,sz,v;ll sum;}tr[Maxn]; void add(int u,int v) { e[tot]={v,head[u]}; head[u]=tot++; } int find(int x) { if(x!=tr[x].fa) tr[x].fa=find(tr[x].fa); return tr[x].fa; } int Merge(int x,int y) { if((!x)||(!y)) return x+y; if(tr[x].v<tr[y].v) swap(x,y); tr[x].r=Merge(tr[x].r,y); if(tr[tr[x].l].dist<tr[tr[x].r].dist) swap(tr[x].l,tr[x].r); tr[x].dist=tr[tr[x].r].dist+1; tr[x].sz=tr[tr[x].l].sz+tr[tr[x].r].sz+1; tr[x].sum=tr[tr[x].l].sum+tr[tr[x].r].sum+tr[x].v; return x; } int Del(int x) { int rt=tr[x].fa=tr[tr[x].l].fa=tr[tr[x].r].fa=Merge(tr[x].l,tr[x].r); return rt; } void dfs(int rt) { for(int i=head[rt];i;i=e[i].next) { dfs(e[i].to); srt[rt]=tr[srt[rt]].fa=tr[srt[e[i].to]].fa=Merge(srt[rt],srt[e[i].to]); } while(tr[srt[rt]].sum>m) srt[rt]=Del(srt[rt]); // printf("%d: %d\n",rt,tr[srt[rt]].sz); ans=max(ans,1ll*a[rt].l*tr[srt[rt]].sz); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d%d",&a[i].fa,&a[i].c,&a[i].l); tr[++cnt]={cnt,0,0,0,1,a[i].c,a[i].c},srt[i]=cnt; if(!a[i].fa) RT=i; else add(a[i].fa,i); }dfs(RT); printf("%lld\n",ans); return 0; }

D - Sequence (Day1)

应该说是最有价值的一题了.
首先先做一个经典tricktricktrick,将每个aia_iai−i-ii,从而将严格单调变成不降.
然后,考虑特殊情形,例如单减,显然要全取中位数.
那么我们将所有极大单减分量先组起来,再去考虑如何将几个分量糅合从而满足题目的不降条件.
画图易证:::如果不满足条件,那么直接往前糅合一定最优.
具体实现考虑用栈,每次加入就将他不断向前糅合,糅合用左偏树实现.

#include<bits/stdc++.h> # define Maxn 1000005 # define ll long long using namespace std; int n,a[Maxn],b[Maxn],tot; int s[Maxn],top,id[Maxn],All[Maxn]; ll ans; struct Node{int fa,l,r,dist,sz,v;}tr[Maxn]; int Merge(int x,int y) { if((!x)||(!y)) return x+y; if(tr[x].v<tr[y].v) swap(x,y); tr[x].r=Merge(tr[x].r,y); if(tr[tr[x].l].dist<tr[tr[x].r].dist) swap(tr[x].l,tr[x].r); tr[x].dist=tr[tr[x].r].dist+1; tr[x].sz=tr[tr[x].l].sz+tr[tr[x].r].sz+1; return x; } int Del(int x) { int rt=tr[x].fa=tr[tr[x].l].fa=tr[tr[x].r].fa=Merge(tr[x].l,tr[x].r); return rt; } int L[Maxn],R[Maxn]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]),a[i]-=i; tr[++tot]={tot,0,0,0,1,a[i]}; int now=tot,sum=1,sl=i; while(top&&tr[s[top]].v>tr[now].v) { now=tr[now].fa=tr[s[top]].fa=Merge(now,s[top]); sum+=All[top--]; while(tr[now].sz>(sum+1)/2) now=Del(now); }s[++top]=now,All[top]=sum; } int k=1; for(int i=1;i<=top;i++) { for(int j=1;j<=All[i];j++) { b[k++]=tr[s[i]].v; ans+=abs(a[k-1]-b[k-1]); } } printf("%lld\n",ans); for(int i=1;i<=n;i++) printf("%d\n",b[i]+i); return 0; }

E - 城池攻占

维护每个城池上的骑士,然后就没了.

#include<bits/stdc++.h> # define Maxn 300005 # define ll long long using namespace std; int n,m,srt[Maxn],cnt; int head[Maxn],tot=1; struct Edge{int to,next;}e[Maxn]; struct Node{int fa,a;ll h,v;}a[Maxn]; struct Tree{int fa,l,r,dist,sz,id;ll v,lz1=1,lz2=0;}tr[Maxn<<1]; void add(int u,int v) { e[tot]={v,head[u]}; head[u]=tot++; } int s[Maxn],c[Maxn],dep[Maxn],sum1[Maxn],sum2[Maxn]; void Put(int rt,ll v1,ll v2) { tr[rt].v=tr[rt].v*v1+v2; tr[rt].lz1*=v1,tr[rt].lz2*=v1,tr[rt].lz2+=v2; } void Push(int rt) { Put(tr[rt].l,tr[rt].lz1,tr[rt].lz2); Put(tr[rt].r,tr[rt].lz1,tr[rt].lz2); tr[rt].lz1=1,tr[rt].lz2=0; } int Merge(int x,int y) { Push(x),Push(y); if((!x)||(!y)) return x+y; if(tr[x].v>tr[y].v) swap(x,y); tr[x].r=Merge(tr[x].r,y); if(tr[tr[x].l].dist<tr[tr[x].r].dist) swap(tr[x].l,tr[x].r); tr[x].dist=tr[tr[x].r].dist+1; tr[x].sz=tr[tr[x].l].sz+tr[tr[x].r].sz+1; return x; } int Del(int x) { int rt=tr[x].fa=tr[tr[x].l].fa=tr[tr[x].r].fa=Merge(tr[x].l,tr[x].r); return rt; } void dfs(int rt) { for(int i=head[rt];i;i=e[i].next) { dep[e[i].to]=dep[rt]+1,dfs(e[i].to); srt[rt]=tr[srt[rt]].fa=tr[srt[e[i].to]].fa=Merge(srt[rt],srt[e[i].to]); } while(tr[srt[rt]].sz&&tr[srt[rt]].v<a[rt].h) { sum1[rt]++,sum2[tr[srt[rt]].id]=dep[c[tr[srt[rt]].id]]-dep[rt]; srt[rt]=Del(srt[rt]); } if(a[rt].a==0) Put(srt[rt],1,a[rt].v); else Put(srt[rt],a[rt].v,0); } int main() { scanf("%d%d",&n,&m),cnt=n; for(int i=1;i<=n;i++) scanf("%lld",&a[i].h); for(int i=2;i<=n;i++) { scanf("%d%d%lld",&a[i].fa,&a[i].a,&a[i].v); add(a[i].fa,i); } for(int i=1;i<=m;i++) { scanf("%d%d",&s[i],&c[i]),cnt++; tr[cnt].fa=tr[cnt].l=tr[cnt].r=tr[cnt].dist=0,tr[cnt].sz=1,tr[cnt].id=i,tr[cnt].v=s[i]; srt[c[i]]=tr[srt[c[i]]].fa=tr[cnt].fa=Merge(srt[c[i]],cnt); }dfs(1); while(tr[srt[1]].sz) { sum2[tr[srt[1]].id]=dep[c[tr[srt[1]].id]]+1; srt[1]=Del(srt[1]); } for(int i=1;i<=n;i++) printf("%d\n",sum1[i]); for(int i=1;i<=m;i++) printf("%d\n",sum2[i]); return 0; }

总结

左偏树主要的下手点应是 “合并”,思路上讲究的是 “循序渐进”,逐步想到 “合并”.

代码需要注意的BUG

(1). 删除节点时的原根节点父亲赋值应赋成新根.
(2). 若有懒标记,一定要在最开始下放.

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/26 23:19:31

AWS-Nuke终极指南:如何快速彻底清理AWS云环境资源

在云计算时代&#xff0c;AWS账户中积累的未使用资源不仅会造成成本浪费&#xff0c;还可能带来安全隐患。AWS-Nuke作为一款强大的开源工具&#xff0c;专门用于批量删除AWS账户中的所有资源&#xff0c;是云环境管理的终极解决方案。 【免费下载链接】aws-nuke Remove all the…

作者头像 李华
网站建设 2025/12/27 9:56:19

novelWriter终极入门指南:从零开始掌握小说写作神器

novelWriter终极入门指南&#xff1a;从零开始掌握小说写作神器 【免费下载链接】novelWriter novelWriter is an open source plain text editor designed for writing novels. It supports a minimal markdown-like syntax for formatting text. It is written with Python 3…

作者头像 李华
网站建设 2025/12/13 8:37:19

Git-Appraise分布式代码评审系统:从入门到精通

Git-Appraise分布式代码评审系统&#xff1a;从入门到精通 【免费下载链接】git-appraise Distributed code review system for Git repos 项目地址: https://gitcode.com/gh_mirrors/gi/git-appraise Git-Appraise是一款革命性的分布式代码评审工具&#xff0c;它彻底改…

作者头像 李华
网站建设 2025/12/13 8:36:45

从零到一:用Dify工作流构建智能应用的实战指南

从零到一&#xff1a;用Dify工作流构建智能应用的实战指南 【免费下载链接】Awesome-Dify-Workflow 分享一些好用的 Dify DSL 工作流程&#xff0c;自用、学习两相宜。 Sharing some Dify workflows. 项目地址: https://gitcode.com/GitHub_Trending/aw/Awesome-Dify-Workflo…

作者头像 李华
网站建设 2025/12/24 6:55:08

3分钟获取Hadoop权威指南全套学习宝典

3分钟获取Hadoop权威指南全套学习宝典 【免费下载链接】Hadoop权威指南第四版资源下载分享 本仓库提供《Hadoop权威指南&#xff08;第四版&#xff09;》的中文PDF、英文PDF以及配套源代码的下载。该书由Tom White编写&#xff0c;王海、华东、刘喻、吕粤海等人翻译&#xff0…

作者头像 李华
网站建设 2025/12/18 2:47:08

完整指南:如何使用Obsidian-Douban插件同步豆瓣数据

完整指南&#xff1a;如何使用Obsidian-Douban插件同步豆瓣数据 【免费下载链接】obsidian-douban an obsidian plugin that can pull data from douban to your markdown file 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-douban Obsidian-Douban是一个强大…

作者头像 李华