P2146 [NOI2015]软件包管理器

P2146 [NOI2015]软件包管理器

树剖入门题

题目大意:

操作一:把u到根节点的路径全部点亮

操作二:把u以及所有u的子树节点熄灭

求每一次操作之后改变了多少点的亮暗?

裸的树剖,对于我这样的菜鸡入门人士十分合适

大力树剖时,跳链是最关键的(其实线段树不怎么难,大概PJ难度)

il void cgn(int x,int y,int SUM){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        T.upd(1,n,1,dfn[top[x]],dfn[x],SUM);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    T.upd(1,n,1,dfn[x],dfn[y],SUM); 
}

大力跳链代码

第一次 if(dep[top[x]]<dep[top[y]]) swap(x,y); 打错了,没有加"top"

这是一个本质错误,对于跳链过程,比的是一整条链,而不是单个点

其他没什么好说的了

代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
const int N=100005;
int n,m;
int fa[N];//父亲编号 
int size[N];//子树大小 
int son[N];//重儿子编号 
int dep[N];//节点深度 
int belong[N];//所属重链 
int cont=0;//重链条数 
int top[N];//节点所在重链链顶  
int dfn[N];//dfs序 
int indexy=0;//时间戳 
int rk[N];//dfs序对应原节点 
int hed[N],tal[N<<1],val[N<<1],nxt[N<<1],cnt=0;
struct Sugment_Tree{
    int t[N<<2];//安装的个数
    int LZT[N<<2];//懒标记 
    #define mid (l+r)/2
    Sugment_Tree(){memset(LZT,-1,sizeof(LZT));}
    il void push_up(int num){
        t[num]=t[num<<1]+t[num<<1|1];
    }
    il void push_down(int l,int r,int num){//懒标记下传 
        if(LZT[num]==-1) return;
        LZT[num<<1]=LZT[num];
        LZT[num<<1|1]=LZT[num];
        t[num<<1]=(mid-l+1)*LZT[num];
        t[num<<1|1]=(r-(mid+1)+1)*LZT[num];
        LZT[num]=-1;
    }
    il void build(int l,int r,int num){
        if(l==r){
            t[num]=0;
            return;
        }
        build(l,mid,num<<1);
        build(mid+1,r,num<<1|1); 
        push_up(num);
    } 
    il void upd(int l,int r,int num,int L,int R,int SUM){
        if(l>R||r<L) return;
        if(l>=L&&r<=R){
            t[num]=(r-l+1)*SUM;//反转 
            LZT[num]=SUM;
            return;
        }
        push_down(l,r,num);
        upd(l,mid,num<<1,L,R,SUM);
        upd(mid+1,r,num<<1|1,L,R,SUM);
        push_up(num); 
    }
    il int ask(int l,int r,int num,int L,int R){//询问区间1的个数 
        if(l>R||r<L) return 0;
        if(l>=L&&r<=R) return t[num];
        push_down(l,r,num);
        return ask(l,mid,num<<1,L,R)+ask(mid+1,r,num<<1|1,L,R); 
    }
}T;
il void dfs1(int u){
    size[u]=1;
    for(int i=hed[u];i;i=nxt[i]){
        int v=tal[i];
        if(v==fa[u]) continue;
        dep[v]=dep[u]+1;
        dfs1(v);
        size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
}
il void dfs2(int u,int t){
    top[u]=t;
    dfn[u]=++indexy;
    rk[dfn[u]]=u;
    if(!son[u]) return;
    dfs2(son[u],t);
    for(int i=hed[u];i;i=nxt[i]){
        int v=tal[i];
        if(v==fa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}
il void addege(int x,int y){
    cnt++;
    tal[cnt]=y;
    nxt[cnt]=hed[x];
    hed[x]=cnt;
}
il void cgn(int x,int y,int SUM){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        T.upd(1,n,1,dfn[top[x]],dfn[x],SUM);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    T.upd(1,n,1,dfn[x],dfn[y],SUM); 
}
int main(){
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        int x;
        scanf("%d",&x);
        ++x;
        fa[i]=x;//处理父亲 
        addege(x,i);
        addege(i,x);
    }
    dep[1]=1;
    dfs1(1);//第一遍dfs 
    dfs2(1,1);
    T.build(1,n,1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        char c;
        int x; 
        cin>>c;
        int val1,val2;
        val1=T.t[1];
        if(c=='i'){
            cin>>c>>c>>c>>c>>c>>c;
            scanf("%d",&x);//操作子树
            x++; 
            cgn(1,x,1);
            val2=T.t[1];
            printf("%d\n",abs(val1-val2));
        }
        else{
            cin>>c>>c>>c>>c>>c>>c>>c>>c;
            scanf("%d",&x);
            x++;
            T.upd(1,n,1,dfn[x],dfn[x]+size[x]-1,0);
            val2=T.t[1];
            printf("%d\n",abs(val1-val2));
        }
    }
    return 0;
} 

 

posted @ 2019-10-03 20:11  QYJ060604  阅读(145)  评论(0编辑  收藏  举报