Luogu P2146

由于对于每一个软件包有且只有一个依赖的软件包,且依赖关系不存在环。

很显然这是一个树形的结构。

再看题目要求的操作,安装实际上对应的是覆盖根节点到当前节点的路径,卸载则是覆盖该节点的整颗子树。

对于这样的操作,树链剖分+线段树可以很轻松地维护。

值得注意的是,根节点编号为0,我为了方便操作,把所有节点的编号都加了1

线段树的懒标记在没有使用的情况下应该标记为-1,因为0代表的是整个区间被覆盖为0。不能判断为标记为0就不进行push_down,因为卸载之后其子树上的所有节点都应该被标记为0。而对于完全没有使用过的标记,如果置为0,则会影响到子树上被安装的节点。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson root<<1
#define rson root<<1|1
#define mid ((l+r)>>1)
using namespace std;
struct data
{
int to,next;
}edge[200005];
int cnt,head[100005],tag[400005],tree[400005],d[100005],f[100005],id[100005],size[100005];
int wson[100005],top[100005],n,x,y,q;
string st;
inline void add(int x,int y)
{
edge[++cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt;
}
inline void push_down(int root,int l,int r)
{
if (tag[root]==-1) return ;
tree[lson]=(mid-l+1)*tag[root];
tree[rson]=(r-mid)*tag[root];
tag[lson]=tag[rson]=tag[root];
tag[root]=-1;
}
inline void push_up(int root)
{
tree[root]=tree[lson]+tree[rson];
}
void segupd(int root,int l,int r,int al,int ar,int flag)
{
if (ar<l||r<al) return ;
if (al<=l&&r<=ar)
{
tag[root]=flag;
if (tag[root]) tree[root]=r-l+1;
else tree[root]=0;
return;
}
push_down(root,l,r);
segupd(lson,l,mid,al,ar,flag);
segupd(rson,mid+1,r,al,ar,flag);
push_up(root);
}
int query(int root,int l,int r,int al,int ar)
{
if (ar<l||r<al) return 0;
if (al<=l&&r<=ar)
return tree[root];
int ret=0;
push_down(root,l,r);
ret+=query(lson,l,mid,al,ar);
ret+=query(rson,mid+1,r,al,ar);
return ret;
}
void dfs1(int now,int fa,int deep)
{
d[now]=deep;
f[now]=fa;
size[now]++;
for (int i=head[now];i;i=edge[i].next)
{
int v=edge[i].to;
if (v==fa) continue;
dfs1(v,now,deep+1);
size[now]+=size[v];
if (size[v]>size[wson[now]]) wson[now]=v;
}
}
void dfs2(int now,int t)
{
top[now]=t;
id[now]=++cnt;
if (wson[now]) dfs2(wson[now],t);
for (int i=head[now];i;i=edge[i].next)
{
int v=edge[i].to;
if (wson[now]==v||v==f[now]) continue;
dfs2(v,v);
}
}
int inst(int now)
{
int tmp=query(1,1,n,id[top[now]],id[now]);
int ans=0;
while (!tmp&&now!=0)
{
ans+=id[now]-id[top[now]]+1;
segupd(1,1,n,id[top[now]],id[now],1);
now=f[top[now]];
if (now==0) return ans;
tmp=query(1,1,n,id[top[now]],id[now]);
}
if (now!=0)
{
ans+=id[now]-id[top[now]]+1-tmp;
segupd(1,1,n,id[top[now]],id[now],1);
}
return ans;
}
inline int uninst(int now)
{
int ans=query(1,1,n,id[now],id[now]+size[now]-1);
segupd(1,1,n,id[now],id[now]+size[now]-1,0);
return ans;
}
void build(int root,int l,int r)
{
if (l==r)
{
tree[root]=0;
tag[root]=-1;
return ;
}
build(lson,l,mid);
build(rson,mid+1,r);
push_up(root);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;i++)
{
scanf("%d",&x);
add(i+1,x+1);
add(x+1,i+1);
}
dfs1(1,0,0);
cnt=0;
dfs2(1,1);
build(1,1,n);
scanf("%d\n",&q);
for (int i=1;i<=q;i++)
{
cin>>st;
scanf("%d",&x);
if (st=="install")
printf("%d\n",inst(x+1));
else
printf("%d\n",uninst(x+1));
}
return 0;
}

【Luogu P2146】软件包管理器的更多相关文章

  1. Luogu P2146 软件包管理器(树链剖分+线段树)

    题意 给定\(n\)个软件包,每个软件包都有一个依赖软件包,安装一个软件包必须安装他的依赖软件包,卸载一个软件包必须先卸载所有依赖于它的软件包.给定\(m\)此操作,每次一个操作\(install/u ...

  2. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  3. 【Luogu】P2146软件包管理器(树链剖分)

    题目链接 上午跟rqy学了一道超难的概率题,准备颓一会,于是水了这么一道水题. 话说这题真的是模板啊.数据范围正好,描述特别贴近(都不给你绕弯子的),连图都给你画出来,就差题目描述加一句“树链剖分模板 ...

  4. 洛谷 - P2146 - 软件包管理器 - 重链剖分

    https://www.luogu.org/problem/P2146 继续重链剖分. 这里好像很好懂,每次安装软件就区间改值赋值整个路径是1,然后比较前后的sum值变化就可以了.事实上后一次的sum ...

  5. 洛谷 [P2146] 软件包管理器

    树剖 将一个软件是否安装,看作是sum数组的0或1,对于每个操作前后sum[1]的变化,就是所求 #include <iostream> #include <cstdio> # ...

  6. NOI2015 软件包管理器(树链剖分+线段树)

    P2146 软件包管理器 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决 ...

  7. P2146 [NOI2015]软件包管理器

    题目链接:https://www.luogu.org/problemnew/show/P2146 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安 ...

  8. 洛谷 P2146 [NOI2015]软件包管理器 解题报告

    P2146 [NOI2015]软件包管理器 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软 ...

  9. [Luogu 2146] NOI2015 软件包管理器

    [Luogu 2146] NOI2015 软件包管理器 树剖好题. 通过对题目的分析发现,这些软件构成一棵树,\(0\) 是树根. 每下载一个软件,需要下载根到这个软件的路径上的所有软件: 每卸载一个 ...

  10. 洛谷 P2146 [NOI2015]软件包管理器 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 输出样例#1: 输入样例#2: 输出样例#2: 说明 说明 思路 AC代码 总结 题面 题目链接 P ...

随机推荐

  1. codeblocks 调试不停止的解决办法。

    CB的工程路径不能有中文,也不能有空格. 所以一定要全英文路径,而且空格要用下划线代替. 否则,调试的时候,codeblocks不会在断点处停止.

  2. ORACLE定时备份方案

    ORACLE定时备份方案 采用ORACLE的EXP工具,实现ORACLE的备份:采用LINUX的服务crond实现定时功能. 1 编辑SH,实现备份功能 #vi oracle_backup.sh,输入 ...

  3. Javascript对this对象的理解

    在JavaScript中this表示函数运行的时候自动生成的一个内部对象,只能在函数内部使用,下面是一个简单的例子: function test(){ alert(this == window); } ...

  4. LNMP与LAMP的工作原理

    LAMP的实现原理 LAMP=Linux+Apache+Mysql+PHP.​#工作原理:浏览器向服务器发送http请求,服务器 (Apache) 接受请求,由于php作为Apache的组件模块也会一 ...

  5. React Ref 和 React forwardRef

    Ref 和Dom,Ref是reference(引用)的简写. 能力:大多数情况下,props前递可以解决一切问题,但是依然有需要触达React实例或者Dom节点的情况,这时候应该使用React Ref ...

  6. MongoDB分页查询优化方法

    在网上看到很多关于MongoDB分页查询优化的文章,如出一辙.笔者自己实际生产中也遇到此问题,所以看了很多篇文章,这里分享一篇简明扼要的文章分享给大家,希望对大家在使用MongoDB时有所帮助. 凡事 ...

  7. Exceptionless—本地部署

    参考:https://blog.csdn.net/shiyaru1314/article/details/76176236 自己采坑: ES 1.7.5版本不好使.使用最新版本6.X以上版本也不行 用 ...

  8. MIT线性代数:14.正交向量和子空间

  9. 等距结点下的Newton插值多项式系数计算(向前差分)

    插值多项式的牛顿法 1.为何需要牛顿法? ​ 使用Lagrange插值法不具备继承性.当求好经过\(({x_0},{y_0})-({x_n},{y_n})\)共n+1个点的插值曲线时候,如果再增加一个 ...

  10. [考试反思]1024csp-s模拟测试86:消耗

    %%%两个没素质的和一个萌两小时AK 最近貌似总是可以比较快速的拿下T1,然后T2打到考试结束... T1是套路题没什么好说的. T2是一个比较蠢的博弈题,我花了很长时间干各种乱七八糟的事 什么打表啊 ...