zoukankan      html  css  js  c++  java
  • NOI2015 软件包管理器

    题意:

    给定一棵$n$节点的有根树,现在有两种操作.

    $1)$给定$x$,询问$x$节点到根路径上没被标记的点的个数,并把路径上所有点标记.

    $2)$给定$x$,询问$x$子树内被标记的点的个数,并把子树内所有点的标记撤销.

    $n<=10^{5}$

    题解:

    题目要求维护点到根的路径以及点的子树的信息.是树链剖分的裸题.

    复杂度为$O(nlog^{2}n)$

    注意注意注意【重要的事情说三遍】

    在判断重儿子有一句

    if(sz[y]>sz[son[x]])son[x]=y;

     如果编号从$1$开始没问题,$son[x]$初始为$0$,$sz[0]=0$.

    但是题目所给节点的编号从$0$开始!!

    所以$sz[0]$不是$0$!!!!所以很多点就没有重儿子了!!所以就超时了!!!

    为了保险起见,尽量把节点的编号从$1$开始!

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<ctime>
    #include<cstdlib>
    #include<cmath>
    #include<string>
    #include<vector>
    #include<map>
    #include<queue>
    #include<bitset>
    #define ll long long
    #define debug(x) cout<<#x<<"  "<<x<<endl;
    #define db(x,y)cout<<#x<<" "<<#y<<" "<<x<<" "<<y<<endl;
    using namespace std;
    inline void rd(int &res){
        res=0;char c;
        while(c=getchar(),c<48);
        do res=(res<<1)+(res<<3)+(c^48);
        while(c=getchar(),c>=48);
    }
    inline void print(int x){
        if(!x)return ;
        print(x/10);
        putchar((x%10)^48);
    }
    inline void sc(int x){
        if(x<0){x=-x;putchar('-');}
        print(x);
        if(!x)putchar('0');
        putchar('
    ');
    }
    inline void Max(int &x,int y){if(x<y)x=y;}
    inline void Min(int &x,int y){if(x>y)x=y;}
    const int M=1e5+5;
    int res=0,n,m,sz[M],w[M],tot=0,fa[M],top[M],son[M],head[M],ec=2,to[M],nxt[M];
    int dep[M],L[M],R[M];
    struct Seg{
        int t[M<<2],f[M<<2];
        void down(int l,int mid,int r,int p){
            if(f[p]==-1)return;
            t[p<<1]=f[p]*(mid-l+1);
            t[p<<1|1]=f[p]*(r-mid);
            f[p<<1]=f[p<<1|1]=f[p];
            f[p]=-1;
        }
        void build(int l,int r,int p){
            f[p]=-1;
            if(l==r)return;
            int mid=l+r>>1;
            build(l,mid,p<<1),build(mid+1,r,p<<1|1);
        }
        void upd(int L,int R,int l,int r,int v,int p){
            if(L==l&&R==r){
                res+=t[p];        
                t[p]=v*(r-l+1);
                f[p]=v;
                return;
            }
            int mid=L+R>>1;
            down(L,mid,R,p);
            if(r<=mid)upd(L,mid,l,r,v,p<<1);
            else if(l>mid)upd(mid+1,R,l,r,v,p<<1|1);
            else upd(L,mid,l,mid,v,p<<1),upd(mid+1,R,mid+1,r,v,p<<1|1);
            t[p]=t[p<<1]+t[p<<1|1];
        }
    }T;
    void ins(int a,int b){
        to[ec]=b;nxt[ec]=head[a];head[a]=ec++;
    }
    void dfs(int x){
        sz[x]=1;
        for(int i=head[x];i;i=nxt[i]){
            int y=to[i];
            dep[y]=dep[x]+1;
            dfs(y);
            sz[x]+=sz[y];
            if(!son[x]||sz[y]>sz[son[x]])son[x]=y;//得到大儿子 
        }
    }
    void build(int x,int tp){
        top[x]=tp;
        L[x]=w[x]=++tot;
        if(son[x])build(son[x],tp);
        for(int i=head[x];i;i=nxt[i]){
            if(to[i]!=son[x])build(to[i],to[i]);
        }
        R[x]=tot;
    }
    int add_anc(int a){//得到a的祖先的路径 
        int sum=dep[a];
        res=0;
        while(~a){//求出没有装的个数 并且把每个点都装上 
            T.upd(1,n,w[top[a]],w[a],1,1);//求出已经有的点的个
            a=fa[top[a]];
        }
    //    printf("%d %d
    ",sum,res);
        return sum-res;
    }
    int del_son(int a){//删除自己的所有儿子 
        res=0;
        T.upd(1,n,L[a],R[a],0,1);
        return res; 
    }
    int main(){
    
        rd(n);fa[0]=-1;
        char s[20];int i,j,a;
        for(i=1;i<n;i++){
            rd(fa[i]);
            ins(fa[i],i);
        }
        dep[0]=1;
        dfs(0);
        build(0,0);
        rd(m);
        T.build(1,n,1);
        while(m--){
            scanf("%s",s);rd(a);
            if(s[0]=='i'){ 
                sc(add_anc(a));
            }
            else{
                sc(del_son(a));
            }
        }
        return 0;
    }
    View Code

    $By LIN452$

    $2017.06.07$

  • 相关阅读:
    使用NPOI将多张图片导入execl
    Oracle计算时间差函数
    Oracle_spatial的函数介绍[转]
    FDO error:Failed to label layer(XXX) for class Default
    您属于哪个版本的程序员[转]
    关于oracle-12514错误的修改方法
    ArcGis在Oracle中常用的sql
    读取XML绑定TreeNode
    HTML中图片热区的使用
    如何查看目前正在使用的Windows10是哪个版本?
  • 原文地址:https://www.cnblogs.com/Lay-with-me/p/6955887.html
Copyright © 2011-2022 走看看