zoukankan      html  css  js  c++  java
  • 【洛谷P2146】【LOJ#2130】【BZOJ4196】软件包管理器【树链剖分】

    题目大意:

    题目链接:https://www.luogu.org/problem/P2146
    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。


    思路:

    • 默写树剖板子qwqqwq

    显然,删除一个软件xx就相当于要删除所有依赖他的软件,也就是求xx的子树大小;增加一个软件xx就相当于要把路径1x1-x全部增加,即求一条路径的节点个数。
    每一次都修改树显然是不够优秀的。我们可以考虑直接把树建好,然后每一个节点维护一个权值0/10/1,表示这个节点现在是否真实存在。
    删除一个节点就只要求出以该节点为根的子树内权值为1的节点个数,增加一个节点就只要求路径1x1-x的权值为0的点的个数。
    那么问题就是一个树剖的板子了。线段树维护区间和,每次询问之后打一个lazylazy标记即可。
    感觉现在做的树剖题目都很裸啊,到时候要拐一点弯的题就完了啊qwqqwq
    时间复杂度O(nlog2n)O(nlog^2 n)


    代码:

    成功写进150150行233

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=200010;
    int fa[N],son[N],dep[N],top[N],size[N],id[N],head[N];
    int n,tot,cnt,m,x;
    char ch[20];
    
    struct edge
    {
    	int next,to;
    }e[N];
    
    struct Treenode
    {
    	int l,r,sum,lazy;
    };
    
    struct Tree
    {
    	Treenode tree[N*4];
    	
    	void pushdown(int x)
    	{
    		if (tree[x].lazy!=-1)
    		{
    			tree[x*2].lazy=tree[x*2+1].lazy=tree[x].lazy;
    			if (!tree[x].lazy) tree[x*2].sum=tree[x*2+1].sum=0;
    			else
    			{
    				tree[x*2].sum=tree[x*2].r-tree[x*2].l+1;
    				tree[x*2+1].sum=tree[x*2+1].r-tree[x*2+1].l+1;
    			}
    			tree[x].lazy=-1;
    		}
    	}
    	
    	void pushup(int x)
    	{
    		tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
    	}
    	
    	void build(int x)
    	{
    		tree[x].lazy=-1;
    		if (tree[x].l==tree[x].r) return;
    		int mid=(tree[x].l+tree[x].r)>>1;
    		tree[x*2].l=tree[x].l;
    		tree[x*2].r=mid;
    		tree[x*2+1].l=mid+1;
    		tree[x*2+1].r=tree[x].r;
    		build(x*2); build(x*2+1);
    	}
    	
    	int update(int x,int l,int r,int val)
    	{
    		if (tree[x].l==l && tree[x].r==r)
    		{
    			int s=tree[x].sum;
    			tree[x].lazy=val;
    			if (!val) tree[x].sum=0;
    				else tree[x].sum=tree[x].r-tree[x].l+1;
    			return s;
    		}
    		pushdown(x);
    		int mid=(tree[x].l+tree[x].r)>>1,ans=0;
    		if (r<=mid) ans=update(x*2,l,r,val);
    		else if (l>mid) ans=update(x*2+1,l,r,val);
    		else ans=update(x*2,l,mid,val)+update(x*2+1,mid+1,r,val);
    		pushup(x);
    		return ans;
    	}
    }Tree;
    
    void add(int from,int to)
    {
    	e[++tot].to=to;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dfs1(int x)
    {
    	size[x]=1; dep[x]=dep[fa[x]]+1;
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int y=e[i].to;
    		dfs1(y);
    		size[x]+=size[y];
    		if (size[y]>size[son[x]]) son[x]=y;
    	}
    }
    
    void dfs2(int x,int tp)
    {
    	top[x]=tp; id[x]=++cnt;
    	if (son[x]) dfs2(son[x],tp);
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int y=e[i].to;
    		if (y!=son[x]) dfs2(y,y);
    	}
    }
    
    int insert(int x,int y)
    {
    	int sum=0;
    	while (top[x]!=top[y])
    	{
    		if (dep[top[x]]<dep[top[y]]) swap(x,y);
    		sum+=id[x]-id[top[x]]+1-Tree.update(1,id[top[x]],id[x],1);
    		x=fa[top[x]];
    	}
    	if (dep[x]<dep[y]) swap(x,y);
    	sum+=id[x]-id[y]+1-Tree.update(1,id[y],id[x],1);
    	return sum;
    }
    
    int del(int x)
    {
    	return Tree.update(1,id[x],id[x]+size[x]-1,0);
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for (int i=2;i<=n;i++)
    	{
    		scanf("%d",&fa[i]);
    		fa[i]++;
    		add(fa[i],i);
    	}
    	dfs1(1); dfs2(1,1);
    	Tree.tree[1].l=1; Tree.tree[1].r=n;
    	Tree.build(1);
    	scanf("%d
    ",&m);
    	while (m--)
    	{
    		scanf("%s%d",ch+1,&x);
    		x++;
    		if (ch[1]=='i')
    			printf("%d
    ",insert(1,x));
    		else
    			printf("%d
    ",del(x));
    	}
    	return 0;
    }
    
  • 相关阅读:
    [离散数学]集合3.1、3.2、3.3
    Hadoop YARN ResourceManager 未授权访问漏洞复现
    dns域传送漏洞
    文件包含漏洞详解
    XXE漏洞详解
    常见cms
    IP地址详解
    帧详解
    IP包头内容详解
    SSRF漏洞详解
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998043.html
Copyright © 2011-2022 走看看