zoukankan      html  css  js  c++  java
  • 【NOI2015T2】软件包管理器-树链剖分维护路径和子树信息

    测试地址:软件包管理器

    做法:根据条件构图,可以看出原图只有N-1条边,而且不存在环,推断出原图是一棵树。如果把一个软件包依赖的软件包看做它的父亲,那么这就是一棵以0为根的有根树。然后我们再分析操作如何处理。设每个点的点权为0或1,为0表示未安装,为1表示已安装。对于install操作,我们可以看做询问从询问点到根路径上的点数减去路径上点权之和,然后修改从询问点到根的路径上所有点权为1。对于uninstall操作,我们可以看做询问以询问点为根的子树上的点权之和,然后修改以询问点为根的子树上的所有点权为0。维护树上的路径信息我们显然可以用树链剖分来做,问题是维护子树的信息。我们回顾一下树链剖分往线段树中加点的过程,发现整个过程就是一个DFS,所以我们知道线段树中点的排列是按DFS序的。所以我们可以记录进入和离开每个点时的时刻,这两个时刻中间的点就是以这个点为根的子树上的点,是一个连续的区间,很方便用线段树维护。树链剖分的复杂度是O(nlogn),每个install操作复杂度为O(log^2 n),每个uninstall操作复杂度为O(logn),所以总复杂度为O(nlogn+qlog^2 n),可以通过全部数据。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,q,start[100010],end[100010],first[100010]={0},tot=0,t;
    int son[100010],siz[100010],dep[100010],fa[100010],top[100010],h[100010];
    char op[30];
    struct edge {int v,next;} e[200010];
    struct segnode
    {
      int p,sum;
    }seg[300010];
    
    void insert(int a,int b)
    {
      e[++tot].v=b,e[tot].next=first[a],first[a]=tot;
    }
    
    void buildtree(int no,int l,int r)
    {
      seg[no].p=-1;seg[no].sum=0;
      if (l==r) return;
      int mid=(l+r)>>1;
      buildtree(no<<1,l,mid);
      buildtree(no<<1|1,mid+1,r);
    }
    
    void pushdown(int no,int l,int r)
    {
      int mid=(l+r)>>1;
      if (seg[no].p!=-1)
      {
        seg[no<<1].p=seg[no<<1|1].p=seg[no].p;
    	if (seg[no].p)
    	{
    	  seg[no<<1].sum=mid-l+1;
    	  seg[no<<1|1].sum=r-mid;
    	}
    	else seg[no<<1].sum=seg[no<<1|1].sum=0;
        seg[no].p=-1;
      }
    }
    
    void pushup(int no)
    {
      seg[no].sum=seg[no<<1].sum+seg[no<<1|1].sum;
    }
    
    void modify(int no,int l,int r,int s,int t,int val)
    {
      if (l>=s&&r<=t)
      {
        seg[no].p=val;
    	if (seg[no].p) seg[no].sum=r-l+1;
    	else seg[no].sum=0;
    	return;
      }
      int mid=(l+r)>>1;
      pushdown(no,l,r);
      if (s<=mid) modify(no<<1,l,mid,s,t,val);
      if (t>mid) modify(no<<1|1,mid+1,r,s,t,val);
      pushup(no);
    }
    
    int query(int no,int l,int r,int s,int t)
    {
      if (l>=s&&r<=t) return seg[no].sum;
      int mid=(l+r)>>1,ss=0;
      pushdown(no,l,r);
      if (s<=mid) ss+=query(no<<1,l,mid,s,t);
      if (t>mid) ss+=query(no<<1|1,mid+1,r,s,t);
      return ss;
    }
    //以上是线段树部分
    void dfs1(int v)
    {
      son[v]=-1,siz[v]=1;
      for(int i=first[v];i;i=e[i].next)
      {
        dep[e[i].v]=dep[v]+1;
    	fa[e[i].v]=v;
    	dfs1(e[i].v);
    	if (son[v]==-1||siz[e[i].v]>siz[son[v]]) son[v]=e[i].v;
    	siz[v]+=siz[e[i].v];
      }
    }
    
    void dfs2(int v,int tp)
    {
      top[v]=tp;h[v]=++tot;
      start[v]=tot;
      if (son[v]!=-1) dfs2(son[v],tp);
      for(int i=first[v];i;i=e[i].next)
        if (e[i].v!=son[v]) dfs2(e[i].v,e[i].v);
      end[v]=tot;
    }
    
    void treemodify(int x,int y,int val)
    {
      while(top[x]!=top[y])
      {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
    	modify(1,1,n,h[top[x]],h[x],val);
    	x=fa[top[x]];
      }
      if (dep[x]>dep[y]) swap(x,y);
      modify(1,1,n,h[x],h[y],val);
    }
    
    int treequery(int x,int y)
    {
      int ans=0;
      while(top[x]!=top[y])
      {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
    	ans+=query(1,1,n,h[top[x]],h[x]);
    	x=fa[top[x]];
      }
      if (dep[x]>dep[y]) swap(x,y);
      ans+=query(1,1,n,h[x],h[y]);
      return ans;
    }
    //以上是树链剖分部分
    int main()
    {
      scanf("%d",&n);
      for(int i=1,a;i<n;i++)
      {
        scanf("%d",&a);
    	insert(a,i);
      }
      
      fa[0]=-1;dep[0]=0;
      dfs1(0);
      tot=0;t=1;
      dfs2(0,0);
      buildtree(1,1,n);
      
      scanf("%d",&q);
      for(int i=1,x;i<=q;i++)
      {
        scanf("%s%d",op,&x);
    	if (op[0]=='i')
    	{
    	  printf("%d
    ",dep[x]+1-treequery(0,x));
    	  treemodify(0,x,1);
    	}
    	if (op[0]=='u')
    	{
    	  printf("%d
    ",query(1,1,n,start[x],end[x]));
    	  modify(1,1,n,start[x],end[x],0);
    	}
      }
      
      return 0;
    }
    


  • 相关阅读:
    SCILAB简介[z]
    UG OPEN API编程基础 2约定及编程初步
    Office 2003与Office 2010不能共存的解决方案
    UG OPEN API 编程基础 3用户界面接口
    NewtonRaphson method
    UG OPEN API编程基础 13MenuScript应用
    UG OPEN API编程基础 14API、UIStyler及MenuScript联合开发
    UG OPEN API编程基础 4部件文件的相关操作
    UG OPEN API编程基础 1概述
    16 UG Open的MFC应用
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793735.html
Copyright © 2011-2022 走看看