[NOI2015]软件包管理器 —— 树链剖分
作者:互联网
题目描述
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,……,A[m-1]依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0。
输入格式
从文件manager.in中读入数据。
输入文件的第1行包含1个整数n,表示软件包的总数。软件包从0开始编号。
随后一行包含n−1个整数,相邻整数之间用单个空格隔开,分别表示1,2,3,⋯,n−2,n−1号软件包依赖的软件包的编号。
接下来一行包含1个整数q,表示询问的总数。之后q行,每行1个询问。询问分为两种:
install x:表示安装软件包x
uninstall x:表示卸载软件包x
你需要维护每个软件包的安装状态,一开始所有的软件包都处于未安装状态。
对于每个操作,你需要输出这步操作会改变多少个软件包的安装状态,随后应用这个操作(即改变你维护的安装状态)。
输出格式
输出到文件manager.out中。
输出文件包括q行。
输出文件的第i行输出1个整数,为第i步操作中改变安装状态的软件包数。
输入输出样例
输入 #1复制
7 0 0 0 1 1 5 5 install 5 install 6 uninstall 1 install 4 uninstall 0输出 #1复制
3 1 3 2 3输入 #2复制
10 0 1 2 1 3 0 0 3 2 10 install 0 install 3 uninstall 2 install 7 install 5 install 9 uninstall 9 install 4 install 1 install 9输出 #2复制
1 3 2 1 3 1 1 1 0 1说明/提示
【样例说明 1】
一开始所有的软件包都处于未安装状态。
安装5号软件包,需要安装0,1,5三个软件包。
之后安装6号软件包,只需要安装6号软件包。此时安装了0,1,5,6四个软件包。
卸载1号软件包需要卸载1,5,6三个软件包。此时只有0号软件包还处于安装状态。
之后安装4号软件包,需要安装1,4两个软件包。此时0,1,4处在安装状态。最后,卸载0号软件包会卸载所有的软件包。`
【数据范围】
【时限1s,内存512M】
树剖后的建树理解
树链剖分的基础就不讲了,建树及查询就是把一段重链或轻链当做一段区间求距离(树剖跑完后的重链及轻链是连续的),从而加快查询速度
思路
卸载:算以该点为根节点的子树中的已下载的点,即查询 quary2( id[ x ] , id[ x ] +Size[ x ] - 1 , 1 )
[ id[ x ] , id[ x ] +Size[ x ] - 1 ] 是 x 子树的区间
下载:就是算从根到该点的路径上已下载的点的个数,再用该点深度减去个数,即 ans_i = dep[ x ] - sum1
代码
消化理解,树剖毒瘤。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#define N 100005
using namespace std ;
int n , m , ans ;
int dep[N] , fa[N] , son[N] , Size[N] ;
int top[N] , id[N] , be[N] , cnt ;//id为点x的DFS序,be为DFS序对应的点
vector <int> G[N] ;
struct node {
int l , r , sum ;
int lazy ;
} Tree[4*N] ;
void pushup( int x ) {//更新
int lson = 2*x , rson = 2*x+1 ;
Tree[x].sum = Tree[lson].sum + Tree[rson].sum ;
}
void pushdown( int x ) {//下放懒标记
if( Tree[x].lazy == 1 ) {
Tree[x].lazy = 0 ;
Tree[x*2].sum = Tree[x*2].r-Tree[x*2].l+1 ;
Tree[x*2+1].sum = Tree[x*2+1].r-Tree[x*2+1].l+1 ;//更新左右儿子
Tree[x*2].lazy = Tree[x*2+1].lazy = 1 ;
return ;
}
if( Tree[x].lazy == 2 ) {
Tree[x].lazy = 0 ;
Tree[x*2].sum = Tree[x*2+1].sum = 0 ;//更新左右儿子
Tree[x*2].lazy = Tree[x*2+1].lazy = 2 ;
}
}
void build( int l, int r , int x ) {//建线段树
if( l == r ) {
Tree[x].lazy = 0 ;
Tree[x].l = Tree[x].r = l ;
Tree[x].sum = 0 ;
return ;
}
Tree[x].sum = 0 , Tree[x].lazy = 0 ;
Tree[x].l = l , Tree[x].r = r ;
int mid = (l+r)/2 ;
build(l,mid,x*2);
build(mid+1,r,x*2+1);
pushup(x) ;
}
int quary1( int l , int r , int x ) {//下载
if( l > r )
swap(l,r) ;
if( l <= Tree[x].l && r >= Tree[x].r ) {
int sum = Tree[x].sum ;
Tree[x].sum = Tree[x].r-Tree[x].l+1 ;//下载赋值
Tree[x].lazy = 1 ;//懒标记
return sum ;
}
int mid = (Tree[x].l+Tree[x].r)/2 ;
pushdown(x) ;//下放懒标记
int sum = 0 ;
if( l <= mid )
sum += quary1(l,r,x*2) ;
if( r >= mid+1 )
sum += quary1(l,r,2*x+1) ;
pushup(x) ;//更新
return sum ;
}
int quary2( int l , int r , int x ) {//卸载
if( l > r )
swap(l,r) ;
if( l <= Tree[x].l && r >= Tree[x].r ) {
int sum = Tree[x].sum ;
Tree[x].sum = 0 ;//卸载清零
Tree[x].lazy = 2 ;//懒标记
return sum ;
}
int mid = (Tree[x].l+Tree[x].r)/2 ;
pushdown(x);//下放懒标记
int sum = 0 ;
if( l <= mid )
sum += quary2(l,r,x*2) ;
if( r >= mid+1 )
sum += quary2(l,r,2*x+1) ;
pushup(x) ;//更新
return sum ;
}
void DFS1( int x , int f , int deep ) {
fa[x] = f ;
dep[x] = deep ;
Size[x] = 1 ;
for( int i = 0 ; i < G[x].size() ; ++ i ) {
int s = G[x][i] ;
if( s == f )
continue;
DFS1( s,x,deep+1 );
Size[x] += Size[s] ;
if( Size[s] > Size[son[x]] || !son[x] )
son[x] = s ;
}
}
void DFS2( int x , int T ) {
top[x] = T ;
cnt ++ ;
id[x] = cnt ;
be[cnt] = x ;
if( !son[x] )
return ;
DFS2( son[x] , T );
for( int i = 0 ; i < G[x].size() ; ++ i ) {
int s = G[x][i] ;
if( s == son[x] || s == fa[x] )
continue ;
DFS2(s,s);
}
}
int Get_sum( int x , int y ) {
int sum = 0 ;
while( top[x] != top[y] ) {
if( dep[x] < dep[y] )
swap(x,y) ;
sum += quary1( id[x],id[top[x]],1 );
x = fa[top[x]] ;
}
sum += quary1( id[x],id[y],1 );
return sum ;
}
int main() {
scanf("%d", &n );
for( int i = 1 ; i < n ; ++ i ) {
int x ;
scanf("%d", &x );
G[i].push_back(x) ;
G[x].push_back(i) ;
}
cnt = 0 ;
DFS1(0,-1,1);
DFS2(0,0) ;
build(1,n,1);
scanf("%d", &m );
while( m -- ) {
string Fuck ;
cin >> Fuck ;
int x ;
scanf("%d", &x );
if( Fuck[0] == 'i' ) {
ans = Get_sum(x,0);
printf("%d\n", dep[x]-ans );
}
else {
ans = quary2( id[x] , id[x]+Size[x]-1 , 1 );
printf("%d\n", ans ) ;
}
}
}
标签:lazy,管理器,int,sum,Tree,树链,NOI2015,软件包,安装 来源: https://blog.csdn.net/qq_44013342/article/details/101058094