[Luogu 2146] NOI2015 软件包管理器
[Luogu 2146] NOI2015 软件包管理器
树剖好题。
通过对题目的分析发现,这些软件构成一棵树,\(0\) 是树根。
每下载一个软件,需要下载根到这个软件的路径上的所有软件;
每卸载一个软件,需要删除这个软件构成的子树上的所有软件。
因此我们可以 HLD,然后用「0/1 线段树」来维护。
最初每一个点的点权都是 \(0\)。
下载 \(x\):根到 \(x\) 的路径上,所有点权改为 \(1\)。
卸载 \(x\):\(x\) 构成的子树上,所有点权改为 \(0\)。
每次操作前后线段树树根的值(即整棵树的和)的绝对值,就是这一次更新的软件数。
为了方便我直接把 \(0 \sim n-1\) 改成 \(1 \sim n\) 去做啦。
就这样,代码如下。
#include <cstdio>
#include <cstring>
const int MAXN=100010,MAXM=200010;
int n,q;
class HLD
{
public:
HLD(int num=0,int cnt=0):num(num),cnt(cnt)
{
memset(vis,0,sizeof vis);
memset(head,0,sizeof head);
}
void Init(void)
{
for(int i=2,x;i<=n;++i)
{
scanf("%d",&x);
AddEdges(i,x+1);
}
DFS1(1,1),DFS2(1,1),SgT.Build(1,1,n);
}
int Install(int i)
{
int ans=0;
ans-=SgT.Sum(),ChangePath(i);
printf("%d ",ans);
return ans+SgT.Sum();
}
int Uninstall(int i)
{
int ans=0;
ans+=SgT.Sum(),ChangeSubtree(i);
printf("%d ",ans);
return ans-SgT.Sum();
}
private:
bool vis[MAXN];
int num,cnt,head[MAXN];
struct node
{
int v,d,ft,top,son,size,DFN;
}s[MAXN];
struct edge
{
int nxt,to;
edge(int nxt=0,int to=0):nxt(nxt),to(to){}
}e[MAXM];
class SegmentTree
{
public:
void Build(int i,int l,int r)
{
s[i]=node(l,r,0);
if(l==r)
{
s[i].v=0;
return;
}
int j=i<<1,mid=l+r>>1;
Build(j,l,mid),Build(j|1,mid+1,r),PushUp(i);
}
void Change(int i,int l,int r,bool v)
{
if(l==s[i].l && r==s[i].r)
{
Modify(i,v);
return;
}
if(s[i].lazy^10)
PushDown(i);
int j=i<<1,mid=s[i].l+s[i].r>>1;
if(r<=mid)
Change(j,l,r,v);
else if(l>mid)
Change(j|1,l,r,v);
else
Change(j,l,mid,v),Change(j|1,mid+1,r,v);
PushUp(i);
}
int Sum(void)
{
return s[1].v;
}
private:
struct node
{
int v,l,r,lazy;
node(int l=0,int r=0,int lazy=0):l(l),r(r),lazy(lazy){}
}s[MAXN<<2];
void Modify(int i,int v)
{
s[i].v=v ? s[i].r-s[i].l+1 : 0;
s[i].lazy=v;
}
void PushUp(int i)
{
int j=i<<1;
s[i].v=s[j].v+s[j|1].v;
}
void PushDown(int i)
{
int j=i<<1;
Modify(j,s[i].lazy),Modify(j|1,s[i].lazy);
s[i].lazy=10;
}
}SgT;
void AddEdge(int u,int v)
{
e[++cnt]=edge(head[u],v);
head[u]=cnt;
}
void AddEdges(int u,int v)
{
AddEdge(u,v),AddEdge(v,u);
}
void DFS1(int u,int k)
{
s[u].d=k,s[u].size=1;
for(int i=head[u],v;i;i=e[i].nxt)
if(!s[v=e[i].to].size)
{
DFS1(v,k+1);
s[v].ft=u,s[u].size+=s[v].size;
if(s[v].size>s[s[u].son].size)
s[u].son=v;
}
}
void DFS2(int u,int top)
{
s[u].top=top,s[u].DFN=++num,vis[u]=1;
if(s[u].son)
DFS2(s[u].son,top);
for(int i=head[u],v;i;i=e[i].nxt)
if(!vis[v=e[i].to])
DFS2(v,v);
}
void ChangePath(int x)
{
int a;
while((a=s[x].top)^1)
SgT.Change(1,s[a].DFN,s[x].DFN,1),x=s[a].ft;
SgT.Change(1,1,s[x].DFN,1);
}
void ChangeSubtree(int x)
{
SgT.Change(1,s[x].DFN,s[x].DFN+s[x].size-1,0);
}
}T;
int main(int argc,char *argv[])
{
scanf("%d",&n);
T.Init();
scanf("%d",&q);
for(int i=1,x;i<=q;++i)
{
char s[20];
scanf("\n%s %d",s,&x);
if(s[0]=='i')
printf("%d\n",T.Install(x+1));
else
printf("%d\n",T.Uninstall(x+1));
}
return 0;
}
谢谢阅读。
[Luogu 2146] NOI2015 软件包管理器的更多相关文章
- 【题解】Luogu P2146 [NOI2015]软件包管理器
题面:https://www.luogu.org/problemnew/lists?name=2146 这道题要用树链剖分,我博客里有对树链剖分的详细介绍 这道题就是树链剖分的模板,详细解释见程序. ...
- 【luogu P2146 [NOI2015]软件包管理器】 题解
题目链接:https://www.luogu.org/problemnew/show/P2146 变量名真毒瘤 我真的再也不把l,left,r,right弄反了 反向思维更好做一些 #include ...
- 洛谷 2146 [NOI2015]软件包管理器
[题解] 每个软件只依赖另一个软件,且依赖关系不构成环,那么很容易想到这是树形结构. 我们用1表示以安装,用0表示未安装或已卸载:那么安装一个软件,就是把它到树根的路径上所有的点都改为1:卸载一个软件 ...
- Luogu P2146 [NOI2015]软件包管理器 树剖
卸载:把子树清空: 安装:把自己到$1$的链改为$1$ #include<cstdio> #include<iostream> #include<cstring> ...
- BZOJ 4196: [Noi2015]软件包管理器 [树链剖分 DFS序]
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1352 Solved: 780[Submit][Stat ...
- [BZOJ4196][NOI2015]软件包管理器
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1040 Solved: 603[Submit][Stat ...
- Bzoj 4196: [Noi2015]软件包管理器 树链剖分
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 721 Solved: 419[Submit][Statu ...
- [NOI2015]软件包管理器
4621 [NOI2015]软件包管理器 题目等级 : 钻石 Diamond 题目描述 Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过 ...
- BZOJ_4196_[Noi2015]软件包管理器_树链剖分
BZOJ_4196_[Noi2015]软件包管理器_树链剖分 题意: Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助 ...
随机推荐
- 【树莓派 Raspberry-Pi 】系统安装及一些必要的配置
上周六刚收到我的小电脑,被无线设置卡住了,文章并非原创,参考了几个朋友的折腾经历,自己整理下备忘,也希望能帮到和我一样在树莓派方面小白的人,也希望可以和更多有这方面兴趣的朋友共同交流 0. 操作系统下 ...
- Sublime Text 插件推荐——for web developers
楼主向高大上的: web front-end development engineer (好吧,google就是这样翻译的 ^_^)们推荐 ST 插件,在此抛砖引玉: NO.1 :Emmet (原名: ...
- Java学习个人备忘录之数组
数组 概念:同一种类型数据的集合,其实数组就是一个容器. 数组的好处:可以自动给数组中的元素从0开始编号,方便操作这些元素. 格式1:元素类型[] 数组名 = new 元素类型[元素个数]; 格式2: ...
- 在LaTex中插入电路图的方法(插入图片)
主要的需求是要在文档中插入电路图. 有两种方法,一种是直接在LaTex中绘制电路图,使用的库主要是circ和circuitikz 另一种是在其他软件上绘制电路图,转成特定图像格式后,在Latex中插入 ...
- winform 删除,清空指定文件夹上的所有文件或文件夹
//递归删除文件夹及子文件C#代码: public void DeleteFolder(string dir) { if (Directory.Exists(dir)) //如果存在这个文件夹删除之 ...
- 微信小程序项目笔记以及openId体验版获取问题
公司一直说要搞小程序,说了几个月,最近才算落地,一个很小的项目,就结果来讲,勉强让自己窥得小程序门径. 下面总结一下,为了弄好小程序,所学到的知识,以及项目中遇到的问题以及解决的办法.纯属个人见解. ...
- How To Disable MacBook ProTrackpad
How To Disable MacBook Pro Trackpad how to close macbook pro touchpad? https://www.wikihow.com/Chang ...
- Spring AOP 源码解析
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...
- Bootstrap 轮播图的使用和理解
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...