【洛谷P2146】【LOJ#2130】【BZOJ4196】软件包管理器【树链剖分】

2024-01-30 09:58

本文主要是介绍【洛谷P2146】【LOJ#2130】【BZOJ4196】软件包管理器【树链剖分】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目大意:

题目链接:https://www.luogu.org/problem/P2146
Linux用户和OSX用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的yum,以及OSX下可用的homebrew都是优秀的软件包管理器。

你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,…,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,Am−1依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0。


思路:

  • 默写树剖板子 q w q qwq qwq

显然,删除一个软件 x x x就相当于要删除所有依赖他的软件,也就是求 x x x的子树大小;增加一个软件 x x x就相当于要把路径 1 − x 1-x 1x全部增加,即求一条路径的节点个数。
每一次都修改树显然是不够优秀的。我们可以考虑直接把树建好,然后每一个节点维护一个权值 0 / 1 0/1 0/1,表示这个节点现在是否真实存在。
删除一个节点就只要求出以该节点为根的子树内权值为1的节点个数,增加一个节点就只要求路径 1 − x 1-x 1x的权值为0的点的个数。
那么问题就是一个树剖的板子了。线段树维护区间和,每次询问之后打一个 l a z y lazy lazy标记即可。
感觉现在做的树剖题目都很裸啊,到时候要拐一点弯的题就完了啊 q w q qwq qwq
时间复杂度 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2n)


代码:

成功写进 150 150 150行233

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;const int N=200010;
int fa[N],son[N],dep[N],top[N],size[N],id[N],head[N];
int n,tot,cnt,m,x;
char ch[20];struct edge
{int next,to;
}e[N];struct Treenode
{int l,r,sum,lazy;
};struct Tree
{Treenode tree[N*4];void pushdown(int x){if (tree[x].lazy!=-1){tree[x*2].lazy=tree[x*2+1].lazy=tree[x].lazy;if (!tree[x].lazy) tree[x*2].sum=tree[x*2+1].sum=0;else{tree[x*2].sum=tree[x*2].r-tree[x*2].l+1;tree[x*2+1].sum=tree[x*2+1].r-tree[x*2+1].l+1;}tree[x].lazy=-1;}}void pushup(int x){tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;}void build(int x){tree[x].lazy=-1;if (tree[x].l==tree[x].r) return;int mid=(tree[x].l+tree[x].r)>>1;tree[x*2].l=tree[x].l;tree[x*2].r=mid;tree[x*2+1].l=mid+1;tree[x*2+1].r=tree[x].r;build(x*2); build(x*2+1);}int update(int x,int l,int r,int val){if (tree[x].l==l && tree[x].r==r){int s=tree[x].sum;tree[x].lazy=val;if (!val) tree[x].sum=0;else tree[x].sum=tree[x].r-tree[x].l+1;return s;}pushdown(x);int mid=(tree[x].l+tree[x].r)>>1,ans=0;if (r<=mid) ans=update(x*2,l,r,val);else if (l>mid) ans=update(x*2+1,l,r,val);else ans=update(x*2,l,mid,val)+update(x*2+1,mid+1,r,val);pushup(x);return ans;}
}Tree;void add(int from,int to)
{e[++tot].to=to;e[tot].next=head[from];head[from]=tot;
}void dfs1(int x)
{size[x]=1; dep[x]=dep[fa[x]]+1;for (int i=head[x];~i;i=e[i].next){int y=e[i].to;dfs1(y);size[x]+=size[y];if (size[y]>size[son[x]]) son[x]=y;}
}void dfs2(int x,int tp)
{top[x]=tp; id[x]=++cnt;if (son[x]) dfs2(son[x],tp);for (int i=head[x];~i;i=e[i].next){int y=e[i].to;if (y!=son[x]) dfs2(y,y);}
}int insert(int x,int y)
{int sum=0;while (top[x]!=top[y]){if (dep[top[x]]<dep[top[y]]) swap(x,y);sum+=id[x]-id[top[x]]+1-Tree.update(1,id[top[x]],id[x],1);x=fa[top[x]];}if (dep[x]<dep[y]) swap(x,y);sum+=id[x]-id[y]+1-Tree.update(1,id[y],id[x],1);return sum;
}int del(int x)
{return Tree.update(1,id[x],id[x]+size[x]-1,0);
}int main()
{memset(head,-1,sizeof(head));scanf("%d",&n);for (int i=2;i<=n;i++){scanf("%d",&fa[i]);fa[i]++;add(fa[i],i);}dfs1(1); dfs2(1,1);Tree.tree[1].l=1; Tree.tree[1].r=n;Tree.build(1);scanf("%d\n",&m);while (m--){scanf("%s%d",ch+1,&x);x++;if (ch[1]=='i')printf("%d\n",insert(1,x));elseprintf("%d\n",del(x));}return 0;
}

这篇关于【洛谷P2146】【LOJ#2130】【BZOJ4196】软件包管理器【树链剖分】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/659873

相关文章

【Python知识宝库】上下文管理器与with语句:资源管理的优雅方式

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 文章目录 前言一、什么是上下文管理器?二、上下文管理器的实现三、使用内置上下文管理器四、使用`contextlib`模块五、总结 前言 在Python编程中,资源管理是一个重要的主题,尤其是在处理文件、网络连接和数据库

Apache Tiles 布局管理器

陈科肇 =========== 1.简介 一个免费的开源模板框架现代Java应用程序。  基于该复合图案它是建立以简化的用户界面的开发。 对于复杂的网站,它仍然最简单,最优雅的方式来一起工作的任何MVC技术。 Tiles允许作者定义页面片段可被组装成在运行一个完整的网页。  这些片段,或Tiles,可以用于为了降低公共页面元素的重复,简单地包括或嵌入在其它瓦片,制定了一系列可重复使用

Qt-常用控件(3)-多元素控件、容器类控件和布局管理器

1. 多元素控件 Qt 中提供的多元素控件有: QListWidgetQListViewQTableWidgetQTableViewQTreeWidgetQTreeView xxWidget 和 xxView 之间的区别,以 QTableWidget 和 QTableView 为例. QTableView 是基于 MVC 设计的控件.QTableView 自身不持有数据,使用 QTab

高精度计算(代码加解析,洛谷p1601,p1303)除法待更新

目录 高精度加法 高精度减法 高精度乘法 高精度加法 我们知道在c++语言中任何数据类型都有一定的表示范围。当两个被加数很大时,正常加法不能得到精确解。在小学,我们做加法都采用竖式方法。那么我们也只需要按照加法进位的方式就能得到最终解。 8 5 6+ 2 5 5-------1 1 1 1 加法进位: c[i] = a[i] + b[i];if(c[i] >=

洛谷 凸多边形划分

T282062 凸多边形的划分 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 先整一个半成品,高精度过两天复习一下补上 #include <iostream>#include <algorithm>#include <set>#include <cstring>#include <string>#include <vector>#include <map>

能量项链,洛谷

解释:  环形dp问题还是考虑将环拉直,可以参考我上一篇文章:环形石子合并 [2 3 5 10 2] 3 5 10 将环拉直,[]内是一个有效的区间,可以模拟吸收珠子的过程,         如[2 3 5] <=>(2,3)(3,5)    2是头,3是中间,5是尾 len >= 3:因为最后[2 10 2]是最小的可以合并的有效区间 len <= n + 1因为[2 3

Android SmsManager(短信管理器),发送短信息

AndroidManifest.xml <uses-permission android:name="android.permission.SEND_SMS"/> <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns

Android 电话管理器TelephonyManager,获取网络,SIM卡信息

// 获取系统TelephonyManager对象 TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); AndroidManifest.xml package shortcut.song.com.myapplication;import an

828华为云征文|部署电影收藏管理器 Radarr

828华为云征文|部署电影收藏管理器 Radarr 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 应用场景1.3 性能模式 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Radarr3.1 Radarr 介绍3.2 Docker 环境搭建3.3 Radarr 部署3.4 Radarr 使用 四、总结 一、Flexu

随手记(2)-java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序

问题描述: 在使用Java连接access数据的.mdb文件时候程序报如下错误 java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序     错误原因: 在win7 office2013下报错 解决方法:  查看Java桥连程序连接字符串是否写成{Microsoft Access Driver (*.m