zoukankan      html  css  js  c++  java
  • [UOJ#128][BZOJ4196][Noi2015]软件包管理器

    [UOJ#128][BZOJ4196][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,……,Am−1依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
    现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0。

    输入

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

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

    输出

    输出文件包括q行。

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

    输入示例

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

    输出示例

    3
    1
    3
    2
    3

    数据规模及约定

    n=100000

    q=100000

    题解

    树链剖分 + 线段树裸题。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
    	if(Head == Tail) {
    		int l = fread(buffer, 1, BufferSize, stdin);
    		Tail = (Head = buffer) + l;
    	}
    	return *Head++;
    }
    int read() {
    	int x = 0, f = 1; char c = Getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define maxm 200010
    
    int n, m, head[maxn], nxt[maxm], to[maxm];
    void AddEdge(int a, int b) {
    	to[++m] = b; nxt[m] = head[a]; head[a] = m;
    	return ;
    }
    
    int fa[maxn], son[maxn], dep[maxn], siz[maxn], top[maxn], seg_pos[maxn], dl[maxn], dr[maxn], clo;
    void build(int u) {
    	siz[u] = 1;
    	for(int e = head[u]; e; e = nxt[e]) {
    		dep[to[e]] = dep[u] + 1;
    		build(to[e]);
    		siz[u] += siz[to[e]];
    		if(!son[u] || siz[son[u]] < siz[to[e]]) son[u] = to[e];
    	}
    	return ;
    }
    void gett(int u, int tp) {
    	top[u] = tp; dl[u] = ++clo;
    	if(son[u]) gett(son[u], tp);
    	for(int e = head[u]; e; e = nxt[e]) if(to[e] != son[u]) gett(to[e], to[e]);
    	dr[u] = clo;
    	return ;
    }
    
    int sumv[maxn<<2], setv[maxn<<2];
    void pushdown(int o, int l, int r) {
    	if(l == r || setv[o] == -1){ setv[o] = -1; return ; }
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	setv[lc] = setv[rc] = setv[o];
    	sumv[lc] = setv[o] * (mid - l + 1);
    	sumv[rc] = setv[o] * (r - mid);
    	setv[o] = -1;
    	return ;
    }
    int update(int o, int l, int r, int ql, int qr, int v) {
    	pushdown(o, l, r);
    	if(ql <= l && r <= qr) {
    		int tmp = sumv[o];
    		setv[o] = v;
    		sumv[o] = v * (r - l + 1);
    		return tmp;
    	}
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1, ans = 0;
    	if(ql <= mid) ans += update(lc, l, mid, ql, qr, v);
    	if(qr > mid) ans += update(rc, mid + 1, r, ql, qr, v);
    	sumv[o] = sumv[lc] + sumv[rc];
    	return ans;
    }
    int modifyup(int u) {
    	int res = 0, depu = dep[u];
    	while(u) {
    		res += update(1, 1, n, dl[top[u]], dl[u], 1);
    		u = fa[top[u]];
    	}
    	return depu - res;
    }
    int modifydn(int u) {
    	return update(1, 1, n, dl[u], dr[u], 0);
    }
    
    int main() {
    	n = read();
    	for(int i = 2; i <= n; i++) AddEdge(fa[i] = read() + 1, i);
    	
    	dep[1] = 1; build(1); gett(1, 1);
    	memset(setv, -1, sizeof(setv));
    	int q = read(); char ch;
    	while(q--) {
    		ch = Getchar();
    		while(!isalpha(ch)) ch = Getchar();
    		int u = read() + 1;
    		if(ch == 'i') printf("%d
    ", modifyup(u));
    		if(ch == 'u') printf("%d
    ", modifydn(u));
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    自定义 alert 弹窗
    js控制div内的滚动条的位置
    vue 的 起手式
    d3.js封装文本实现自动换行和旋转平移等功能
    redux
    mui 本地打包
    vue-router 运行机制 及 底层原理
    替代 Navigator 组件
    react-native 创建 ios 项目
    三元运算符
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/7073055.html
Copyright © 2011-2022 走看看