题解:P2146 [NOI2015] 软件包管理器

解题思路

对于两种操作,
install : 求从根节点到当前节点这段路径中没有被安装过的软件数量。
unstall : 求当前子树没有被安装过的软件数量。

很显然,对于这两种操作,树链剖分算法是很不错的选择。

AC 代码

#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline

using namespace std;
using ll = long long;
using ull = unsigned long long;

#define maxn 100005
#define ls (p<<1)
#define rs (p<<1|1)

int n,q,a[maxn];
int fa[maxn],dfn[maxn],top[maxn];
int son[maxn],siz[maxn],deep[maxn];
int dfs_cnt;

struct edge
{
	int v,next;
}e[maxn<<1|1];

int head[maxn],k;

inline void add(int u,int v)
{
	e[k]=(edge){v,head[u]};
	head[u]=k++;
}

void dfs1(int u)
{
	deep[u]=deep[fa[u]]+1;
	son[u]=-1;
	siz[u]=1;
	for(int i=head[u];~i;i=e[i].next)
	{
		dfs1(e[i].v);
		siz[u]+=siz[e[i].v];
		if(son[u]==-1||siz[son[u]]<siz[e[i].v]) son[u]=e[i].v;
	}
}

void dfs2(int u,int t)
{
	top[u]=t;
	dfn[u]=++dfs_cnt;
	if(son[u]==-1) return;
	dfs2(son[u],t);
	for(int i=head[u];~i;i=e[i].next)
		if(e[i].v!=son[u])
			dfs2(e[i].v,e[i].v);
}

struct node
{
	int l,r,tag,lazy;
}tree[maxn<<2|1];

void build(int p,int l,int r)
{
	tree[p].l=l;tree[p].r=r;
	if(l==r)
	{
		tree[p].tag= (l==1)?1:0;
		tree[p].lazy=-1;
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	if(tree[ls].tag!=tree[rs].tag||tree[ls].tag==-1) tree[p].tag=-1;
	else tree[p].tag=tree[ls].tag;
}

inline void push_down(int p)
{
	if(tree[p].lazy==-1) return;
	tree[ls].tag=tree[ls].lazy=tree[rs].tag=tree[rs].lazy=tree[p].lazy;
	tree[p].lazy=-1;
}

void change(int p,int l,int r,int d)
{
	if(l<=tree[p].l&&r>=tree[p].r)
	{
		tree[p].tag=d;
		tree[p].lazy=d;
		return;
	}
	push_down(p);
	int mid=(tree[p].l+tree[p].r)>>1;
	if(l<=mid) change(ls,l,r,d);
	if(r>mid) change(rs,l,r,d);
	if(tree[ls].tag!=tree[rs].tag||tree[ls].tag==-1) tree[p].tag=-1;
	else tree[p].tag=tree[ls].tag;
}

int query(int p,int l,int r,int aim)
{
	if(tree[p].tag!=-1&&l<=tree[p].l&&r>=tree[p].r)
		return tree[p].tag==aim?(tree[p].r-tree[p].l+1):0;
	push_down(p);
	int mid=(tree[p].l+tree[p].r)>>1,ans=0;
	if(l<=mid) ans+=query(ls,l,r,aim);
	if(r>mid) ans+=query(rs,l,r,aim);
	return ans;
}

inline int querypath(int x)
{
	int ans=0;
	while(top[x]!=1)
	{
		ans+=query(1,dfn[top[x]],dfn[x],0);
		change(1,dfn[top[x]],dfn[x],1);
		x=fa[top[x]];
	}
	ans+=query(1,dfn[top[x]],dfn[x],0);
	change(1,dfn[top[x]],dfn[x],1);
	return ans;
}

inline int querytree(int x)
{
	int ans=query(1,dfn[x],dfn[x]+siz[x]-1,1);
	change(1,dfn[x],dfn[x]+siz[x]-1,0);
	return ans;
}

int main()
{
	scanf("%d",&n);
	memset(head,-1,sizeof(head));
	a[1]=1;
	for(int i=2;i<=n;i++)
	{
		scanf("%d",&fa[i]);
		fa[i]++;
		add(fa[i],i);
	}
	dfs1(1);
	dfs2(1,1);
	build(1,1,n);
	scanf("%d",&q);
	char opt[20];int x;
	while(q--)
	{
		scanf("\n%s%d",opt,&x);
		x++;
		if(opt[0]=='i') printf("%d\n",querypath(x));
		else printf("%d\n",querytree(x));
	}
	return 0;
}
posted @ 2025-03-09 21:52  Zheng_iii  阅读(11)  评论(0)    收藏  举报