• 【题解】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;
    }
    
  • 相关阅读:
    Java 中日常使用的 IO 流总结
    NIO 实现非阻塞 Socket 通讯
    Java NIO 的简单介绍和使用
    常用设计模式 -- 一分钟就能学会的门面模式(外观模式)
    Java日志框架介绍和 Slf4j 使用
    Linux学习一
    JavaScript-数组
    javascript
    idea 快捷键汇总
    正则表达式
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/9430808.html
Copyright © 2020-2023  润新知