[BZOJ4196][NOI2005]软件包管理器(链剖+dfs序)

来源:互联网 发布:js 算法 编辑:程序博客网 时间:2024/06/07 13:45

题目:
我是超链接
题解:
dfs序的in和out可以完美的把子树囊括在内,所以在维护的线段树上也是一段连续的区间,可以整体操作
首先关于安装问题,可以用状态0/1来表示
对于根到结点X的查询,非常容易
好了出于对树链剖分更深层次的理解,写一遍数组的意义:
in编号为i的点在线段树数组中的编号,sum编号为i的点在线段树中的存在的孩子个数【in是连接现实和虚拟的门。
添加软件包的时候,由于不是x的子树全部都要添加,必须呈链状修改
但删除就简单多了,呈团状子树全都没啦
代码:

#include <cstdio>#include <cstring>#include <iostream>#define N 100000#define MIN -19e+7using namespace std;int size[N*4],ww[N*4],son[N*4],fa[N*4],deep[N*2+5],delta[N*4+5];int top[N*4],in[N*4],out[N*4],totw=0;int sum[N*4],maxn[N*4],minn[N*4];int next[N*2+5],point[N*2+5],v[N*2+5],tot=0,cnt=0,n;void addline(int x,int y){    ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y;    ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x;}void updata(int now){sum[now]=sum[now<<1]+sum[now<<1|1];}void dfs_1(int now,int dep,int faa){    deep[now]=dep;    fa[now]=faa;    size[now]=1;    int maxx=MIN;    for (int i=point[now];i;i=next[i])      if (v[i]!=faa)      {        dfs_1(v[i],dep+1,now);        size[now]+=size[v[i]];        if (size[v[i]]>maxx)        {            maxx=size[v[i]];            son[now]=v[i];        }      }}void dfs_2(int now,int faa){    if (son[faa]!=now) top[now]=now;    else top[now]=top[faa];    in[now]=++cnt;    if (son[now])    {        dfs_2(son[now],now);        for (int i=point[now];i;i=next[i])          if (v[i]!=son[now] && v[i]!=faa)            dfs_2(v[i],now);    }    out[now]=cnt;}void pushdown(int now,int l,int r,int mid){    if (delta[now]>=0)    {        delta[now<<1]=delta[now];        delta[now<<1|1]=delta[now];        sum[now<<1]=delta[now]*(mid-l+1);        sum[now<<1|1]=delta[now]*(r-mid);        delta[now]=-1;    }}int qurry(int now,int l,int r,int lrange,int rrange){    if (lrange<=l && rrange>=r) return sum[now];        int mid=(l+r)>>1,ans=0;    pushdown(now,l,r,mid);    if (mid>=lrange) ans+=qurry(now<<1,l,mid,lrange,rrange);    if (mid<rrange) ans+=qurry(now<<1|1,mid+1,r,lrange,rrange);    return ans;} void change(int now,int l,int r,int lrange,int rrange,int v){    if (l>=lrange && rrange>=r)    {        delta[now]=v;        sum[now]=v*(r-l+1);        return;    }    int mid=(l+r)>>1;    pushdown(now,l,r,mid);    if (mid>=lrange)change(now<<1,l,mid,lrange,rrange,v);    if (mid<rrange) change(now<<1|1,mid+1,r,lrange,rrange,v);    updata(now);}int work(int u,int v,int id){    int f1=top[u],f2=top[v],summ=0;    while (f1!=f2)    {        if (deep[f1]<deep[f2])         {            swap(f1,f2); swap(u,v);        }        if (id==1) summ+=qurry(1,1,n,in[f1],in[u]);        else change(1,1,n,in[f1],in[u],1);        u=fa[f1];        f1=top[u];    }    if (in[u]<in[v]) swap(u,v);    if (id==1) summ+=qurry(1,1,n,in[v],in[u]);    else change(1,1,n,in[v],in[u],1);    return summ;}int main(){    int i,x,q;    scanf("%d",&n);    for (i=1;i<=n-1;i++)    {        scanf("%d",&x);        addline(i+1,x+1);    }    dfs_1(1,1,0);    dfs_2(1,0);    memset(delta,128,sizeof(delta));    scanf("%d",&q);    for (i=1;i<=q;i++)    {        char st[20];int ans=0;        scanf("%s%d",st,&x);        x++;        if (st[0]=='i')        {            ans=work(1,x,1);            printf("%d\n",deep[x]-ans);            ans=work(1,x,2);        }        else        {            ans=qurry(1,1,n,in[x],out[x]);            printf("%d\n",ans);            change(1,1,n,in[x],out[x],0);        }    }  }
0 0