Description
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。
Input
输入文件的第1行包含1个正整数n,表示软件包的总数。软件包从0开始编号。
随后一行包含n−1个整数,相邻整数之间用单个空格隔开,分别表示1,2,3,…,n−2,n−1号软件包依赖的软件包的编号。
接下来一行包含1个正整数q,表示询问的总数。
之后q行,每行1个询问。询问分为两种:
installx:表示安装软件包x
uninstallx:表示卸载软件包x
你需要维护每个软件包的安装状态,一开始所有的软件包都处于未安装状态。对于每个操作,你需要输出这步操作会改变多少个软件包的安装状态,随后应用这个操作(即改变你维护的安装状态)。
Output
输出文件包括q行。
输出文件的第i行输出1个整数,为第i步操作中改变安装状态的软件包数。
// luogu-judger-enable-o2 #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) #define maxn 100002 using namespace std; int read() { int f=1,x=0; char ss=getchar(); while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();} while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();} return f*x; } void print(int x) { if(x<0){putchar('-');x=-x;} if(x>9)print(x/10); putchar(x%10+'0'); } namespace Seg { #define lson (x << 1) #define rson ((x << 1) | 1) int sumv[maxn << 2], lazy[maxn << 2]; void mark_tag(int l, int r, int x, int delta) { sumv[x] = (r - l + 1) * delta, lazy[x] = delta; } void pushdown(int l, int r, int x) { if(lazy[x] == -1) return ; int mid = (l + r) >> 1; if(mid >= l) mark_tag(l, mid, lson, lazy[x]); if(mid < r) mark_tag(mid + 1, r, rson, lazy[x]); lazy[x] = -1; } int query(int l, int r, int x, int L, int R) { if(l >= L && r <= R) { return sumv[x]; } pushdown(l, r, x); int mid = (l + r) >> 1; int t = 0; if(L <= mid) t += query(l, mid, lson, L, R); if(R > mid) t += query(mid + 1, r, rson, L, R); return t; } void update(int l, int r, int x, int L, int R, int d) { if(l >= L && r <= R) { mark_tag(l, r, x, d); return ; } pushdown(l, r, x); int mid = (l + r) >> 1; if(L <= mid) update(l, mid, lson, L, R, d); if(R > mid) update(mid + 1, r, rson, L, R, d); sumv[x] = sumv[lson] + sumv[rson]; } }; int hd[maxn], to[maxn], nex[maxn], fa[maxn], siz[maxn], top[maxn], hson[maxn], dep[maxn]; int st[maxn], ed[maxn], dfn[maxn]; int edges, n, Q, root = 1, tim; char str[100]; void add(int u, int v) { nex[++edges] = hd[u], hd[u] = edges, to[edges] = v; } void dfs1(int u) { siz[u] = 1, dep[u] = dep[fa[u]] + 1; for(int i = hd[u]; i ; i = nex[i]) { dfs1(to[i]), siz[u] += siz[to[i]]; if(siz[to[i]] > siz[hson[u]]) hson[u] = to[i]; } } void dfs2(int u, int tp) { dfn[u] = ++tim, top[u] = tp; st[u] = tim; if(hson[u]) dfs2(hson[u], tp); for(int i = hd[u]; i ; i = nex[i]) { if(to[i] != hson[u]) dfs2(to[i], to[i]); } ed[u] = tim; } int lookup(int x) { int t = 0; while(x) { t += Seg :: query(1, n, 1, dfn[top[x]], dfn[x]); Seg :: update(1, n, 1, dfn[top[x]], dfn[x], 1); x = fa[top[x]]; } return t; } int main() { // setIO("input"); n=read(); for(int i = 2; i <= n; ++i) { fa[i]=read(), ++fa[i], add(fa[i], i); } dfs1(1), dfs2(1, 1); memset(Seg::lazy, -1, sizeof(Seg :: lazy)); Q=read(); while(Q--) { int u; scanf("%s",str); u=read(); u+=1; if(str[0] == 'i') { print(dep[u] - lookup(u)); printf(" "); } if(str[0] == 'u') { print(Seg :: query(1, n, 1, st[u], ed[u])); Seg :: update(1, n, 1, st[u], ed[u], 0); printf(" "); } } return 0; }