[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 软件包管理器的更多相关文章

  1. 【题解】Luogu P2146 [NOI2015]软件包管理器

    题面:https://www.luogu.org/problemnew/lists?name=2146 这道题要用树链剖分,我博客里有对树链剖分的详细介绍 这道题就是树链剖分的模板,详细解释见程序. ...

  2. 【luogu P2146 [NOI2015]软件包管理器】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2146 变量名真毒瘤 我真的再也不把l,left,r,right弄反了 反向思维更好做一些 #include ...

  3. 洛谷 2146 [NOI2015]软件包管理器

    [题解] 每个软件只依赖另一个软件,且依赖关系不构成环,那么很容易想到这是树形结构. 我们用1表示以安装,用0表示未安装或已卸载:那么安装一个软件,就是把它到树根的路径上所有的点都改为1:卸载一个软件 ...

  4. Luogu P2146 [NOI2015]软件包管理器 树剖

    卸载:把子树清空: 安装:把自己到$1$的链改为$1$ #include<cstdio> #include<iostream> #include<cstring> ...

  5. BZOJ 4196: [Noi2015]软件包管理器 [树链剖分 DFS序]

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1352  Solved: 780[Submit][Stat ...

  6. [BZOJ4196][NOI2015]软件包管理器

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1040  Solved: 603[Submit][Stat ...

  7. Bzoj 4196: [Noi2015]软件包管理器 树链剖分

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 721  Solved: 419[Submit][Statu ...

  8. [NOI2015]软件包管理器

    4621 [NOI2015]软件包管理器  题目等级 : 钻石 Diamond   题目描述 Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过 ...

  9. BZOJ_4196_[Noi2015]软件包管理器_树链剖分

    BZOJ_4196_[Noi2015]软件包管理器_树链剖分 题意: Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助 ...

随机推荐

  1. Cow Contest(最短路floyed传递闭包)

    Description N (1 ≤ N ≤ 100) cows, conveniently numbered 1..N, are participating in a programming con ...

  2. c语言乐曲演奏——《千本樱》

    这个程序着实花费了我好长的时间,我本身对音乐一窍不通,先是跟着girl friend学习了简谱,根据c调44拍的<千本樱>写下了下面的程序. #include<stdio.h> ...

  3. ueditor百度编辑器的赋值方法

    示例: http://ueditor.baidu.com/website/onlinedemo.html 引用代码: window.UMEDITOR_HOME_URL = $CONFIG['domai ...

  4. Java中的线程的优先级

    Java 中线程优先级简介: 1. Java 提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程. 按照线程的优先级决定应该调度哪个线程来执行. 2. 线程的优先级用数字表示, 范围从 1 到 ...

  5. lintcode-32-最小子串覆盖

    最小子串覆盖 给定一个字符串source和一个目标字符串target,在字符串source中找到包括所有目标字符串字母的子串. 注意事项 如果在source中没有这样的子串,返回"" ...

  6. LintCode-70.二叉树的层次遍历 II

    二叉树的层次遍历 II 给出一棵二叉树,返回其节点值从底向上的层次序遍历(按从叶节点所在层到根节点所在的层遍历,然后逐层从左往右遍历) 样例 给出一棵二叉树 {3,9,20,#,#,15,7}, 按照 ...

  7. Gitkraken系列-Gitkraken使用操作

    一个优秀的团队合作离不开git,一个优秀的程序员也离不开git.gitkraken是我在进行软工实践这门课接触到的git的UI界面的工具,它给我留下的印象就是非常好用和方便 怎么个方便法呢? 方便的安 ...

  8. listBox和pictureBox的使用

    重要属性:pictureBox中SizeMode可以更改图像显示的尺寸大小. using System; using System.Collections.Generic; using System. ...

  9. OO的五大原则

    OO的五大原则是指SRP.OCP.LSP.DIP.ISP 1. SRP(Single Responsibility Principle 单一职责原则) 单一职责很容易理解,所谓单一职责,就是一个设计元 ...

  10. c# 调用c++ 使用指针传递的时候

    http://www.cnblogs.com/warensoft/archive/2011/12/09/warenosoft3d.html 上面这篇文章很好解释了. 简单记录一下: 1. 声明  注意 ...