当前位置 博文首页 > swen29的博客:NOI2015 软件包管理器 树剖+线段树

    swen29的博客:NOI2015 软件包管理器 树剖+线段树

    作者:[db:作者] 时间:2021-09-21 20:59

    题目背景是一个安装与卸载软件的系统,软件之间关系是一棵树,以0为根节点。当你安装一个软件时需要先安装它的所有祖先,卸载时则要先卸载整个子树。对每一次操作询问改变状态的软件数目。

    思路:dfs序做树剖,用线段树维护数据。

    #include<iostream>
    #include<vector>
    #include<stdio.h>
    #define ls (id*2)
    #define rs (id*2+1)
    using namespace std;
    vector<int> lin[100005];
    int in[100005],size[100005],fa[100005],top[100005],n,num,ans;
    struct node
    {
        int val;
        int lazy;
    }t[100005*4];
    int abs(int a)
    {
        return a>=0?a:-a;
    }
    void push_down(int id,int l,int mid,int r)
    {
        if (t[id].lazy==-1)return;
        t[ls].lazy=t[id].lazy;
        t[rs].lazy=t[id].lazy;
        t[ls].val=(mid-l+1)*t[id].lazy;
        t[rs].val=(r-mid)*t[id].lazy;
        t[id].lazy=-1;
    }
    void push_up(int id)
    {
        t[id].val=t[ls].val+t[rs].val;
    }
    void build(int id,int l,int r)
    {
        if(l==r)
        {
            t[id].val=0;
            t[id].lazy=-1;//改成-1!切记! 
            return;
        }
        int mid=(l+r)/2;
        build(ls,l,mid);
        build(rs,mid+1,r);
        push_up(id);
    }
    void insert(int id,int l,int r,int L,int R,int V)
    {
        if(r<L||l>R) return;
        if(r<=R && l>=L)
        {
            ans+=abs(V*(r-l+1)-t[id].val);
            t[id].val=V*(r-l+1);
            t[id].lazy=V;
            return;
        }
        int mid=(l+r)/2;
        push_down(id,l,mid,r);
        insert(ls,l,mid,L,R,V);
        insert(rs,mid+1,r,L,R,V);
        push_up(id);
    }
    void dfs1(int x,int pre)
    {
        in[x]=++num;
        fa[x]=pre;
        for (int i=0;i<lin[x].size();i++)
        {
            int nex=lin[x][i];
            if (nex==pre)   continue;
            dfs1(nex,x);
        }
        size[x]=num-in[x]+1;//必须+1,否则dfs2中判断叶子节点很麻烦。
    }
    void dfs2(int x,int t)
    {
        in[x]=++num;
        top[x]=t;
        if (size[x]==1) return;//叶子节点直接返回,否则会死循环(不能用size[x]=0做!)
        int msize=0,heavy=0;//都要赋初始值!
        for (int i=0;i<lin[x].size();i++)
        {
            int nex=lin[x][i];
            if (nex==fa[x]) continue;
            if (size[nex]>msize)
            {
                msize=size[nex];
                heavy=nex;
            }
        }
        dfs2(heavy,t);//先走重儿子,其他随意
        for (int i=0;i<lin[x].size();i++)
        {
            int nex=lin[x][i];
            if (nex==fa[x] || nex==heavy) continue;
            dfs2(nex,nex);
        }
    }
    int main()
    {
        cin>>n;
        for (int i=1;i<n;i++)
        {
            int a;
            cin>>a;//编号都+1,防止爆线段树 
            lin[a+1].push_back(i+1);
            lin[i+1].push_back(a+1);
        }
        num=0;  dfs1(1,0);
        num=0;  dfs2(1,1);
        int q;  
        cin>>q;
        char s[15];
        while (q--)
        {
            int a;
            scanf("%s",s);//一定不要用cin!!!!T了半个小时...
            scanf("%d",&a);
            a++;
            if (s[0]=='i')
            {
                ans=0;
                while (a!=0)
                {
                    insert(1,1,n,in[top[a]],in[a],1);
                    a=fa[top[a]];
                } 
                printf("%d\n",ans);
            }
            if (s[0]=='u')
            {
                ans=0;
                insert(1,1,n,in[a],in[a]+size[a]-1,0);
                printf("%d\n",ans);
            }
        }
    }
    cs
    下一篇:没有了