[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】

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

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

安装5号软件包,需要安装0,1,5三个软件包。

之后安装6号软件包,只需要安装6号软件包。此时安装了0,1,5,6四个软件包。

卸载1号软件包需要卸载1,5,6三个软件包。此时只有0号软件包还处于安装状态。

之后安装4号软件包,需要安装1,4两个软件包。此时0,1,4处在安装状态。最后,卸载0号软件包会卸载所有的软件包。`

【数据范围】

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

【时限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 ) ;
		}
	}
}

 

 

 

 

 

 

 

上一篇:Python 中拼音库 PyPinyin 的用法!这个库有点意思哈!


下一篇:【Lazy资产管理系统v1.0】2019年10月19日发布测试版