BZOJ4196:[NOI2015]软件包管理器——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=4196
https://www.luogu.org/problemnew/show/P2146
你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,⋯,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,A[m-1]依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0。
题面很长,耐心看完就知道这是道树剖的板子题。
(然而不会求子树和的我还是去看了题解)
我们把安装的权值为1,未安装为0。
对于下载操作只需要查询该点到根节点的路程-1的个数。
对于卸载操作只需要查询该点的子树的1的个数。
(当然别忘了二者的修改。)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e5+;
const int INF=;
inline int read(){
int X=,w=;char ch=;
while(ch<''||ch>''){w|=ch=='-';ch=getchar();}
while(ch>=''&&ch<='')X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int to,nxt;
}edge[*N];
struct tree{
int lazy,sum;
}t[*N];
int head[N],cnt,tot,n;
inline void add(int u,int v){
edge[++cnt].to=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
int fa[N],dep[N],size[N],son[N],top[N],pos[N],idx[N];
void dfs1(int u){
size[u]=;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u])continue;
fa[v]=u;dep[v]=dep[u]+;
dfs1(v);
size[u]+=size[v];
if(!son[u]||size[v]>size[son[u]])son[u]=v;
}
return;
}
void dfs2(int u,int anc){
tot++;
pos[u]=tot;
idx[tot]=u;
top[u]=anc;
if(!son[u])return;
dfs2(son[u],anc);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
return;
}
inline void pushdown(int a,int l,int r){
int mid=(l+r)>>;
if(t[a].lazy!=-){
t[a*].lazy=t[a*+].lazy=t[a].lazy;
t[a*].sum=t[a].lazy*(mid-l+);
t[a*+].sum=t[a].lazy*(r-mid);
t[a].lazy=-;
}
return;
}
void modify(int a,int l,int r,int l1,int r1,int v){
if(r1<l||r<l1)return;
if(l1<=l&&r<=r1){
t[a].sum=v*(r-l+);
t[a].lazy=v;
return;
}
int mid=(l+r)>>;
pushdown(a,l,r);
modify(a*,l,mid,l1,r1,v);
modify(a*+,mid+,r,l1,r1,v);
t[a].sum=t[a*].sum+t[a*+].sum;
return;
}
void pathmodify(int u,int v,int c){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;}
modify(,,n,pos[top[u]],pos[u],c);
u=fa[top[u]];
}
if(dep[u]>dep[v]){int t=u;u=v;v=t;}
modify(,,n,pos[u],pos[v],c);
return;
}
inline void nodemodify(int u,int c){
modify(,,n,pos[u],pos[u]+size[u]-,c);
}
int query(int a,int l,int r,int l1,int r1){//线段树区间和
if(r1<l||l1>r)return ;
if(l1<=l&&r<=r1)return t[a].sum;
int mid=(l+r)>>;
pushdown(a,l,r);
return query(a*,l,mid,l1,r1)+query(a*+,mid+,r,l1,r1);
}
int pathquery(int u,int v){//询问(u,v)这条路径的和
if(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;}
return pos[u]-pos[top[u]]+
+pathquery(fa[top[u]],v)-query(,,n,pos[top[u]],pos[u]);
}
if(dep[u]>dep[v]){int t=u;u=v;v=t;}
return pos[v]-pos[u]+-query(,,n,pos[u],pos[v]);
}
inline int nodequery(int u){
return query(,,n,pos[u],pos[u]+size[u]-);
}
void init(){
dep[]=fa[]=;
dfs1();
top[]=idx[]=pos[]=;
tot=;
dfs2(,);
for(int i=;i<*n;i++)t[i].lazy=-;
return;
}
int main(){
n=read();
for(int i=;i<=n;i++){
int v=read()+;
add(i,v);add(v,i);
}
init();
int q=read();
while(q--){
char op[];
scanf("%s",op);
int u=read()+;
if(op[]=='i'){
printf("%d\n",pathquery(u,));
pathmodify(u,,);
}
else{
printf("%d\n",nodequery(u));
nodemodify(u,);
}
}
return ;
}
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
BZOJ4196:[NOI2015]软件包管理器——题解的更多相关文章
- [UOJ#128][BZOJ4196][Noi2015]软件包管理器
[UOJ#128][BZOJ4196][Noi2015]软件包管理器 试题描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管 ...
- [BZOJ4196][NOI2015]软件包管理器(树链剖分)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2166 Solved: 1253[Submit][Sta ...
- [BZOJ4196][NOI2015]软件包管理器
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1040 Solved: 603[Submit][Stat ...
- 【NOI2015】【BZOJ4196】软件包管理器 - 题解
Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖( ...
- [bzoj4196][Noi2015]软件包管理器_树链剖分_线段树
软件包管理器 bzoj-4196 Noi-2015 题目大意:Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件 ...
- BZOJ4196 [Noi2015]软件包管理器 【树剖】
题目 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件 ...
- BZOJ4196[Noi2015]软件包管理器——树链剖分+线段树
题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...
- BZOJ4196: [Noi2015]软件包管理器(树链剖分)
Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖( ...
- [Noi2015]软件包管理器 题解
题目大意: 有n个软件安装包,除第一个以外,其他的要在另一个安装包的基础上安装,且无环,问在安装和卸载某个软件包时,这个操作实际上会改变多少个软件包的安装状态. 思路: 可构成树,用树链剖分,线段树. ...
随机推荐
- UpdateLog
2014-10-20 增加数据适配器,使支持多数据库类型2015-01-08 增加没有主键ID的抽象类,使能自义主键字段实现MODEL 增加虚拟字段转换,将指定函数或语法转换为对象属性,灵活性更大了 ...
- katalon系列三:Project Setting-项目设置
安装完katalon后,用QQ邮箱注册并登陆,然后新建一个项目.点击菜单Project-Project Setting打开项目设置,接下来介绍几个你可能会用到的设置. 1.Text Design-We ...
- jmeter关联三种常用方法
在LR中有自动关联跟手动关联,但在我看来手动关联更准确,在jmeter中,就只有手动关联 为什么要进行关联:对系统进行操作时,本次操作或下一次操作对服务器提交的请求,这参数里边有部分参数需要服务器返回 ...
- Python学习-猜数字游戏
菩萨蛮·黄鹤楼 茫茫九派流中国,沉沉一线穿南北.烟雨莽苍苍,龟蛇锁大江. 黄鹤知何去,剩有游人处.把酒酹滔滔,心潮逐浪高! --coding:UTF-8-- import random secret ...
- 一键部署pxe环境
系统:Centos6.5 环境:VMware Workstation12 #!/bin/bash # Please prepare CentOS ISO image first # root pass ...
- [转]Excel数据转化为sql脚本
在实际项目开发中,有时会遇到客户让我们把大量Excel数据导入数据库的情况.这时我们就可以通过将Excel数据转化为sql脚本来批量导入数据库. 1 在数据前插入一列单元格,用来拼写sql语句. 具体 ...
- 统计学习三:2.K近邻法代码实现(以最近邻法为例)
通过上文可知k近邻算法的基本原理,以及算法的具体流程,kd树的生成和搜索算法原理.本文实现了kd树的生成和搜索算法,通过对算法的具体实现,我们可以对算法原理有进一步的了解.具体代码可以在我的githu ...
- APUE学习笔记3_文件IO
APUE学习笔记3_文件IO Unix中的文件IO函数主要包括以下几个:open().read().write().lseek().close()等.这类I/O函数也被称为不带缓冲的I/O,标准I/O ...
- 导弹拦截与Dilworth定理
这两天被Dilworth.链和反链搞到头昏脑胀,终于有点眉目,现在来总结一下. Dilworth定理说的是:对于一个偏序集,其最少链划分数等于其最长反链的长度. Dilworth定理的对偶定理说的是: ...
- <Effective C++>读书摘要--Resource Management<一>
1.除了内存资源以外,Other common resources include file descriptors, mutex locks, fonts and brushes in graphi ...