【题解】Luogu P2146 [NOI2015]软件包管理器

题面:https://www.luogu.org/problemnew/lists?name=2146

这道题要用树链剖分,我博客里有对树链剖分的详细介绍

这道题就是树链剖分的模板,详细解释见程序。

学完树的dfs序,lca,线段树食用更佳。

不会这些学什么树剖(逃~

#include <bits/stdc++.h> //万能头文件
using namespace std;
int n,q,tot;
int fa[100005],size[100005],dep[100005],son[100005];
int lo[100005],top[100005];
int sum[800005],tag[800005];	
vector <int> allson[100005];
//线段树
void pushup(int x)//更新
{
	sum[x]=sum[x<<1]+sum[(x<<1)+1];
}
void pushdown(int x,int l,int r)//清除懒标记
{
	if(tag[x]!=-1)
	{
		int m=(l+r)>>1;
		int ls=x<<1;
		int rs=ls+1;
		tag[ls]=tag[rs]=tag[x];
		sum[ls]=(m-l+1)*tag[x];
		sum[rs]=(r-m)*tag[x];
		tag[x]=-1; 
	}
}
void update(int x,int l,int r,int L,int R,int v)//修改
{
	if(R<l||r<L)
		return;
	if(L<=l&&r<=R)
	{
		sum[x]=(r-l+1)*v;
		tag[x]=v;
		return;
	}
	pushdown(x,l,r);
	int m=(l+r)>>1;
	update(x<<1,l,m,L,R,v);
	update((x<<1)+1,m+1,r,L,R,v);
	pushup(x);
}
//树链剖分
void change(int x,int y,int v)//类似lca
{
	int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy])
			swap(x,y),swap(fx,fy);
        update(1,1,tot,lo[fx],lo[x],v);
        x=fa[fx],fx=top[x];
    }
    if(lo[x]>lo[y])
		swap(x,y);
    update(1,1,tot,lo[x],lo[y],v);
}
void dfs1(int x)
{
	size[x]=1;
	for(int i=0;i<allson[x].size();++i)
	{
		int v=allson[x][i];
		dep[v]=dep[x]+1;//深度
		dfs1(v);
		size[x]+=size[v];//子树大小
		if(size[v]>size[son[x]])
			son[x]=v;//重儿子
	}
}
void dfs2(int x,int t)
{
	lo[x]=++tot;	
	top[x]=t;//重链父亲
	if(son[x])
		dfs2(son[x],t);
	for(int i=0;i<allson[x].size();++i)
	{
		int v=allson[x][i];
		if(v!=son[x])
			dfs2(v,v);
	}
} 
int main()
{
	memset(tag,-1,sizeof(tag)); //lazy_tag为-1表示没有
	ios::sync_with_stdio(0);
	cin>>n;
	fa[1]=1;
	for(int i=2;i<=n;++i)
	{
		int x;
		cin>>x;
		fa[i]=x+1;
		allson[x+1].push_back(i);
	}
    //预处理
	dfs1(1);
	dfs2(1,1);
	cin>>q;
	while(q--)
	{
		string s;
		int x;
		cin>>s>>x;
		x++;
		int before=sum[1];//改之前
		if(s=="install")
		{
			change(1,x,1);//1到x路上全改成1
			int after=sum[1];//改后
			cout<<fabs(before-after)<<endl;
		}
		else
		{
			update(1,1,n,lo[x],lo[x]+size[x]-1,0);//把x的子树改成0
			int after=sum[1];//改后
			cout<<fabs(before-after)<<endl;
		}
	}
	return 0;
}
posted @ 2018-08-06 16:13  JSOI爆零珂学家yzhang  阅读(201)  评论(0编辑  收藏  举报