ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[NOI2015]软件包管理器 —— 树链剖分

2019-10-24 13:40:39  阅读:314  来源: 互联网

标签:lazy 管理器 int sum Tree 树链 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有