zoukankan      html  css  js  c++  java
  • 【BZOJ4196】[NOI2015] 软件包管理器(树链剖分)

    点此看题面

    大致题意:(n)个软件包,它们的依赖关系形成一棵树。现在,问你安装或卸载一个软件包,会影响多少个软件包的安装状态。

    树链剖分

    这道题应该是 树链剖分 算法比较入门的题目吧。

    对于安装操作

    我们对安装和卸载两种操作分别处理。

    首先,让我们来看一看安装操作应该如何实现。

    考虑到要安装一个软件包,就要把它所依赖的软件包,它的依赖所依赖的软件包,一直到(0)号软件包,全部安装。

    如果将题目中给出的关系看成一棵树,那么也就是要把这个软件包到(0)号节点(即 根节点 )的路径上的所有软件包全部安装。

    用树链剖分应该可以轻松做到这一点。

    对于卸载操作

    我们再来看看如何实现卸载操作。

    考虑卸掉一个软件包,那么所有依赖于它的软件包将全被卸载,所有依赖于依赖于它的软件包的软件包,也将全被卸载,以此类推。

    不难想到,这就相当于把以这个软件包为根的子树内的所有软件包给卸载了。

    用树链剖分应该也能很轻松做到这一点。

    代码

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define abs(x) ((x)<0?-(x):(x))
    #define LL long long
    #define ull unsigned long long
    #define swap(x,y) (x^=y,y^=x,x^=y)
    #define N 100000
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    using namespace std;
    int n,ee=0,lnk[N+5];
    struct edge
    {
    	int to,nxt;
    }e[2*N+5];
    class FIO
    {
    	private:
    		#define Fsize 100000
    		#define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
    		#define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
    		int f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize];double w;
    	public:
    		FIO() {FinNow=FinEnd=Fin;}
    		inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));x*=f;}
    		inline void read_char(char &x) {while(isspace(x=tc()));}
    		inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc()));}
    		inline void write(int x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;}
    		inline void write_char(char x) {pc(x);}
    		inline void write_string(string x) {register int i,len=x.length();for(i=0;i<len;++i) pc(x[i]);}
    		inline void end() {fwrite(Fout,1,FoutSize,stdout);}
    }F;
    class TreeChainDissection//树链剖分模板
    {
    	private:
    		#define PushUp(x) (Sum[x]=Sum[x<<1]+Sum[x<<1|1])
    		#define PushDown(x,ln,rn) ((~flag[x]?(flag[x]?(Sum[x<<1]=ln,Sum[x<<1|1]=rn,flag[x<<1]=flag[x<<1|1]=1):(Sum[x<<1]=Sum[x<<1|1]=flag[x<<1]=flag[x<<1|1]=0)):0),flag[x]=-1)
    		int d,fa[N+5],son[N+5],sz[N+5],Top[N+5],dfn[N+5],fac[N+5],Depth[N+5],Sum[N<<2],flag[N<<2];
    		inline void dfs1(int x)//第一遍dfs预处理
    		{
    			register int i;
    			for(sz[x]=1,i=lnk[x];i;i=e[i].nxt)
    			{
    				if(!(fa[x]^e[i].to)) continue;
    				fa[e[i].to]=x,Depth[e[i].to]=Depth[x]+1,dfs1(e[i].to),sz[x]+=sz[e[i].to];
    				if(sz[e[i].to]>sz[son[x]]) son[x]=e[i].to; 
    			}
    		}
    		inline void dfs2(int x,int col)//第二遍dfs预处理
    		{
    			register int i;
    			if(son[fac[dfn[x]=++d]=x]) dfs2(son[x],col);
    			for(Top[x]=col,i=lnk[x];i;i=e[i].nxt)
    			{
    				if(!(fa[x]^e[i].to&&son[x]^e[i].to)) continue;
    				dfs2(e[i].to,e[i].to);
    			}
    		}
    		inline void Build(int l,int r,int rt)//建树
    		{
    			flag[rt]=-1;
    			if(l^r)
    			{
    				register int mid=l+r>>1;
    				if(l<=mid) Build(l,mid,rt<<1);
    				if(r>mid) Build(mid+1,r,rt<<1|1);
    			}
    		}
    		inline int Update(int l,int r,int rt,int ul,int ur,int x)//将[ul...ur]区间内所有软件包的安装状态修改为x(x=0表示未安装,x=1表示安装),并返回需要改变安装状态的软件包数
    		{
    			register int res=0;
    			if(ul<=l&&r<=ur) {register int t;(x?(t=r-l+1,flag[rt]=1):(t=0,flag[rt]=0)),res=abs(t-Sum[rt]),Sum[rt]=t;return res;}
    			register int mid=l+r>>1;
    			PushDown(rt,mid-l+1,r-mid);
    			if(ul<=mid) res=Update(l,mid,rt<<1,ul,ur,x);
    			if(ur>mid) res+=Update(mid+1,r,rt<<1|1,ul,ur,x);
    			PushUp(rt);
    			return res;
    		}
    	public:
    		inline void Init() {dfs1(1),dfs2(1,1),Build(1,n,1);}
    		inline int uninstall(int pos) {return Update(1,n,1,dfn[pos],dfn[pos]+sz[pos]-1,0);}//卸载一个软件包,相当于修改以这个软件包为根节点的子树内所有软件包安装状态为0
    		inline int install(int pos)//安装一个软件包,相当于修改这个软件包到根节点的所有软件包安装状态为1
    		{
    			register int res=0;
    			while(Top[pos]>>1) res+=Update(1,n,1,dfn[Top[pos]],dfn[pos],1),pos=fa[Top[pos]];
    			return res+Update(1,n,1,1,dfn[pos],1);
    		}
    }S;
    int main()
    {
    	register int i,Q,x;register char op;
    	for(F.read(n),i=2;i<=n;++i) F.read(x),add(x+1,i);
    	for(S.Init(),F.read(Q);Q;--Q)
    	{
    		F.read_char(op),F.read(x);
    		if(op^'u') F.write(S.install(x+1)),F.write_char('
    ');//对于安装操作
    		else F.write(S.uninstall(x+1)),F.write_char('
    ');//对于卸载操作
    	}
    	return F.end(),0;
    }
    
  • 相关阅读:
    浅谈C++ STL中的优先队列(priority_queue)
    哈夫曼树与哈夫曼编码
    Binary Search 的递归与迭代实现及STL中的搜索相关内容
    Prime 算法的简述
    估算网站需要多少宽带方法
    微服务服务拆分步骤
    第一次有人把科创板讲得这么简单明了
    一个人优秀到可怕的三个迹象!一旦具备,必为人中龙凤,大富大贵
    美元加息怎么“剪羊毛”
    英国脱欧的影响
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4196.html
Copyright © 2011-2022 走看看