4196: [Noi2015]软件包管理器

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 721  Solved: 419
[Submit][Status][Discuss]

Description

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。
 

Input

输入文件的第1行包含1个正整数n,表示软件包的总数。软件包从0开始编号。

随后一行包含n−1个整数,相邻整数之间用单个空格隔开,分别表示1,2,3,…,n−2,n−1号软件包依赖的软件包的编号。
接下来一行包含1个正整数q,表示询问的总数。
之后q行,每行1个询问。询问分为两种:
installx:表示安装软件包x
uninstallx:表示卸载软件包x
你需要维护每个软件包的安装状态,一开始所有的软件包都处于未安装状态。对于每个操作,你需要输出这步操作会改变多少个软件包的安装状态,随后应用这个操作(即改变你维护的安装状态)。
 

Output

输出文件包括q行。

输出文件的第i行输出1个整数,为第i步操作中改变安装状态的软件包数。
 

Sample Input

7
0 0 0 1 1 5
5
install 5
install 6
uninstall 1
install 4
uninstall 0

Sample Output

3
1
3
2
3

HINT

一开始所有的软件包都处于未安装状态。

安装 5 号软件包,需要安装 0,1,5 三个软件包。
之后安装 6 号软件包,只需要安装 6 号软件包。此时安装了 0,1,5,6 四个软件包。
卸载 1 号软件包需要卸载 1,5,6 三个软件包。此时只有 0 号软件包还处于安装状态。
之后安装 4 号软件包,需要安装 1,4 两个软件包。此时 0,1,4 处在安装状态。
最后,卸载 0 号软件包会卸载所有的软件包。
 
 
n=100000
q=100000

Source

 题解:
树链剖分。
1为安装,0为未安装。
安装时修改从x到根的路径,输出deep[x]-从x到根的和。
卸载时修改子树,输出子树和。
 #include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
struct node
{
int begin,end,next;
}edge[*MAXN];
struct NODE
{
int left,right,tag,sum;
}tree[MAXN*];
int cnt,Head[MAXN],size[MAXN],deep[MAXN],P[MAXN][],ks[MAXN],js[MAXN],pos[MAXN],belong[MAXN],n,SIZE;
bool vis[MAXN];
void addedge(int bb,int ee)
{
edge[++cnt].begin=bb;edge[cnt].end=ee;edge[cnt].next=Head[bb];Head[bb]=cnt;
}
void addedge1(int bb,int ee)
{
addedge(bb,ee);addedge(ee,bb);
}
int read()
{
int s=,fh=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')fh=-;ch=getchar();}
while(ch>=''&&ch<=''){s=s*+(ch-'');ch=getchar();}
return s*fh;
}
void dfs1(int u)
{
int i,v;
size[u]=;vis[u]=true;
for(i=Head[u];i!=-;i=edge[i].next)
{
v=edge[i].end;
if(vis[v]==false)
{
deep[v]=deep[u]+;
P[v][]=u;
dfs1(v);
size[u]+=size[v];
}
}
}
void Ycl()
{
int i,j;
for(j=;(<<j)<=n;j++)
{
for(i=;i<=n;i++)
{
if(P[i][j-]!=-)P[i][j]=P[P[i][j-]][j-];
}
}
}
void dfs2(int u,int chain)
{
int k=,i,v;
pos[u]=++SIZE;belong[u]=chain;ks[u]=SIZE;
for(i=Head[u];i!=-;i=edge[i].next)
{
v=edge[i].end;
if(deep[v]>deep[u]&&size[v]>size[k])k=v;
}
if(k==){js[u]=SIZE;return;}
dfs2(k,chain);
for(i=Head[u];i!=-;i=edge[i].next)
{
v=edge[i].end;
if(deep[v]>deep[u]&&v!=k)dfs2(v,v);
}
js[u]=SIZE;
}
void Pushup(int k)
{
tree[k].sum=tree[k*].sum+tree[k*+].sum;
}
void Pushdown(int k)
{
int l=k*,r=k*+;
if(tree[k].tag!=-)
{
tree[l].tag=tree[k].tag;tree[r].tag=tree[k].tag;
int mid=(tree[k].left+tree[k].right)/;
tree[l].sum=(mid-tree[k].left+)*tree[k].tag;
tree[r].sum=(tree[k].right-mid)*tree[k].tag;
tree[k].tag=-;
}
}
void Build(int k,int l,int r)
{
tree[k].left=l;tree[k].right=r;tree[k].tag=-;
if(l==r)return;
int mid=(l+r)/;
Build(k*,l,mid);
Build(k*+,mid+,r);
}
int Query_sum(int k,int ql,int qr)
{
if(ql<=tree[k].left&&tree[k].right<=qr)return tree[k].sum;
Pushdown(k);
int mid=(tree[k].left+tree[k].right)/;
if(qr<=mid)return Query_sum(k*,ql,qr);
else if(ql>mid)return Query_sum(k*+,ql,qr);
else return Query_sum(k*,ql,mid)+Query_sum(k*+,mid+,qr);
}
int Solve_sum(int x,int f)
{
int sum=;
while(belong[x]!=belong[f])
{
sum+=Query_sum(,pos[belong[x]],pos[x]);
x=P[belong[x]][];
}
sum+=Query_sum(,pos[f],pos[x]);
return sum;
}
void Change(int k,int l,int r,int C)
{
if(l<=tree[k].left&&tree[k].right<=r){tree[k].tag=C;tree[k].sum=(tree[k].right-tree[k].left+)*C;return;}
Pushdown(k);
int mid=(tree[k].left+tree[k].right)/;
if(r<=mid)Change(k*,l,r,C);
else if(l>mid)Change(k*+,l,r,C);
else {Change(k*,l,mid,C);Change(k*+,mid+,r,C);}
Pushup(k);
}
void Solve_change(int x,int f,int k)
{
while(belong[x]!=belong[f])
{
Change(,pos[belong[x]],pos[x],k);
x=P[belong[x]][];
}
Change(,pos[f],pos[x],k);
}
int main()
{
int bb,i,q,x;
char zs[];
n=read();
memset(Head,-,sizeof(Head));cnt=;
for(i=;i<=n;i++)
{
bb=read();addedge1(bb+,i);
}
memset(P,-,sizeof(P));
deep[]=;
dfs1();Ycl();
dfs2(,);
q=read();
Build(,,n);
for(i=;i<=q;i++)
{
scanf("\n%s",zs);
if(zs[]=='i')
{
x=read();x++;
printf("%d\n",deep[x]-Solve_sum(x,));
Solve_change(x,,);
}
else
{
x=read();x++;
printf("%d\n",Query_sum(,ks[x],js[x]));
Change(,ks[x],js[x],);
}
}
fclose(stdin);
fclose(stdout);
return ;
}

Bzoj 4196: [Noi2015]软件包管理器 树链剖分的更多相关文章

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

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

  2. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  3. 【BZOJ4196】[Noi2015]软件包管理器 树链剖分

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

  4. [BZOJ4196][NOI2015]软件包管理器(树链剖分)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2166  Solved: 1253[Submit][Sta ...

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

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

  6. 【bzoj4196】[Noi2015]软件包管理器 树链剖分+线段树

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

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

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

  8. BZOJ4196[Noi2015]软件包管理器——树链剖分+线段树

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

  9. bzoj4196 [Noi2015]软件包管理器——树链剖分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4196 树链剖分. 代码如下: #include<iostream> #inclu ...

随机推荐

  1. shipyard docker 管理平台

    终于把shipyard弄好了. 我也是根据shipyard的官方文档,做的.在刚开始的时候觉得好难,也遇到了困难,查看了好多文档 但做完之后发现,只需要几步就能简单的配置成功,就能运行了. 修改tcp ...

  2. c语言实现交换两个数的值

    C语言中要实现交换两个数的值,可以有很多种方法,具体如下所述. 不使用中间变量: // 异或, a^=b^=a^=b; a ^= b; b ^= a; a ^= b; // 加减 a = a + b; ...

  3. Python3 基础

    Hello world 在文本编辑器中,键入python执行代码,保存文件为hello.py print('hello, world') 注意print前面不要有任何空格.然后,选择一个目录,例如C: ...

  4. XML1_XML基础

    1.XML的作用 XML 被设计用来传输和存储数据.所以XML 是不作为的. 2.简单的描述 XML 文档形成一种树结构. XML 文档必须包含根元素.该元素是所有其他元素的父元素.XML 文档中的元 ...

  5. 服务器端启动soket多线程

    方法一: Socket socket=null try{ ServerSocket serversocket=nwe ServerSocket(8080) while(true){ socket=se ...

  6. c# .net使用SqlDataReader注意的几点

    转自:http://blog.knowsky.com/258608.htm 1.当SqlDataReader没有关闭之前,数据库连接会一直保持open状态,所以在使用SqlDataReader时,使用 ...

  7. linux JAVA JDK环境配置

    export JAVA_HOME=/usr/local/jdk1.7.0_45export JRE_HOME=/usr/local/jdk1.7.0_45/jreexport CLASSPATH=.: ...

  8. 第 13 章 装饰模式【Decorator Pattern】

    以下内容出自:<<24种设计模式介绍与6大设计原则>> Ladies and gentlemen,May I get your attention,Please?,Now I’ ...

  9. Hibernate Session 获取connection

    Hibernate Session 获取connection 由于最近一个项目要用到一条辅助的SQL ,hibernate里面的SQLQuery API 总的SQL语句不能包含 : 冒号, 固放弃Hi ...

  10. django中form表单的提交:

    一,关于表单: 表单在百度百科的解释:   表单在网页中主要负责数据采集功能.一个表单有三个基本组成部分: 表单标签:这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务器的方法. 表单域 ...