• P2146 [NOI2015]软件包管理器


    P2146 [NOI2015]软件包管理器

    树链剖分

    带区间修改线段树

    install操作:该点到根之间修改成1

    uni操作:该点及其子树修改成0

    每次操作时和上次的相减一下即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cctype>
    using namespace std;
    template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;}
    template <typename T> inline T max(T &a,T &b) {return a>b ?a:b;}
    template <typename T> inline void read(T &x){
        char c=getchar(); x=0; bool f=1;
        while(!isdigit(c)) f= !f||c=='-' ? 0:1,c=getchar();
        while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
        x= f ? x:-x;
    }
    template <typename T> inline void output(T x){
        if(!x) {putchar(48); return ;}
        if(x<0) putchar('-'),x=-x;
        int wt[50],l=0;
        while(x) wt[++l]=x%10,x/=10;
        while(l) putchar(wt[l--]+48);
    }
    typedef int arr[100003];
    int n,m,cnt,tot; char opt[15];
    arr d,fa,siz,bgs,tp,id,hd,ed;
    int nxt[200003],poi[200003],sum[400003],tag[400003];
    inline void add_(int x,int y){
        nxt[ed[x]]=++cnt; hd[x]= hd[x] ? hd[x]:cnt;
        ed[x]=cnt; poi[cnt]=y;
    }
    inline void pushdown(int o,int l,int r){
        if(tag[o]==-1) return ; //没标记要跳出
        int lc=o<<1,rc=o<<1|1,mid=l+((r-l)>>1);
        sum[lc]=tag[o]*(mid-l+1);
        sum[rc]=tag[o]*(r-mid);
        tag[lc]=tag[o]; tag[rc]=tag[o];
        tag[o]=-1;
    }
    inline void build(int o,int l,int r){
        if(l==r) {sum[o]=0; return;}
        int lc=o<<1,rc=o<<1|1,mid=l+((r-l)>>1);
        build(lc,l,mid); build(rc,mid+1,r);
    }
    inline int update(int o,int l,int r,int x1,int x2,int v){
        int res=0;
        if(x1<=l&&r<=x2){
            if(v) res=r-l+1-sum[o],sum[o]=r-l+1,tag[o]=1;
            else res=sum[o],sum[o]=tag[o]=0;
            return res;
        }pushdown(o,l,r);
        int lc=o<<1,rc=o<<1|1,mid=l+((r-l)>>1);
        if(x1<=mid) res+=update(lc,l,mid,x1,x2,v);
        if(x2>mid) res+=update(rc,mid+1,r,x1,x2,v);
        sum[o]=sum[lc]+sum[rc];
        return res;
    }
    inline bool if_del(int o,int l,int r,int x){
        if(l==r) return tag[o]!=1;
        pushdown(o,l,r);
        int lc=o<<1,rc=o<<1|1,mid=l+((r-l)>>1);
        if(x<=mid) return if_del(lc,l,mid,x);
        else return if_del(rc,mid+1,r,x);
    }
    inline void dfs1(int x,int _fa){
        d[x]=d[_fa]+1,fa[x]=_fa,siz[x]=1;
        for(int i=hd[x];i;i=nxt[i])
            if(poi[i]!=_fa){
                dfs1(poi[i],x);
                siz[x]+=siz[poi[i]];
                if(siz[bgs[x]]<siz[poi[i]]) bgs[x]=poi[i];
            }
    }
    inline void dfs2(int x,int _top){
        id[x]=++tot,tp[x]=_top;
        if(siz[x]==1) return;
        dfs2(bgs[x],_top);
        for(int i=hd[x];i;i=nxt[i])
            if(poi[i]!=fa[x]&&poi[i]!=bgs[x])
                dfs2(poi[i],poi[i]);
    }
    inline int ins(int x){
        int res=0;
        while(if_del(1,1,n,id[tp[x]])){ //要调用id映射!!!!!!(-1h)
            res+=update(1,1,n,id[tp[x]],id[x],1);
            if(!fa[tp[x]]) return res;
            x=fa[tp[x]];
        }//优化:向上跳直到第一个值为1的点
        return res+update(1,1,n,id[tp[x]],id[x],1);
    }
    int main(){
        read(n); int q;
        for(int i=1;i<n;++i) read(q),add_(i+1,q+1),add_(q+1,i+1);
        dfs1(1,0); dfs2(1,1); build(1,1,n);
        read(m);
        for(int i=1;i<=m;++i){
            scanf("%s",opt); read(q),++q;
            if(opt[0]=='i') output(ins(q));
            else output(update(1,1,n,id[q],id[q]+siz[q]-1,0));
            putchar('
    ');
        }return 0;
    }
  • 相关阅读:
    你了解JWT吗?
    链接
    C#读取EXCEL发生错误
    TM1637驱动数码管
    Keil中的Code,RO,RW,ZI分别表示什么
    IE 不支持 promise 解决方法
    JS 时间戳转日期格式
    JS input 输入框只能输入 字母和汉字
    小程序 保存图片失败
    小程序充值,方法步骤
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9714225.html
Copyright © 2020-2023  润新知