zoukankan      html  css  js  c++  java
  • BZOJ 4196: [Noi2015]软件包管理器

    二次联通门 : BZOJ 4196: [Noi2015]软件包管理器

    /*
         BZOJ 4196: [Noi2015]软件包管理器
         
         树链剖分
         
         树链剖分 , 用线段树维护链上的和与子树的和
         
         对于1操作, 每次预先查询待修改点x点的深度
         后查询1到x这条链上有多少已安装的, 然后上面的值减下面的值
         
         对于2操作,每次查询以x为根的子树的大小
         修改整颗子树即可..  
         
        说白了其实就是板子题 
    */
    #include <cstdio>
    
    #define Max 500090
    
    inline int min (int a, int b)
    {
        return a < b ? a : b;
    }
    
    inline int max (int a, int b)
    {
        return a > b ? a : b;
    }
    
    inline int swap (int &a, int &b)
    {
        int now = a;
        a = b;
        b = now;
    }
    
    void read (int &now)
    {
        now = 0;
        register char word = getchar ();
        while (word < '0' || word > '9')
            word = getchar ();
        while (word >= '0' && word <= '9')
        {
            now = now * 10 + word - '0';
            word = getchar ();
        }
    }
    
    struct Edge_Type
    {
        struct Edge
        {
            int to;
            int next;
        };
        
        Edge edge[Max << 2];
        
        int Edge_Count;
        int edge_list[Max];
        
        void Add_Edge (int from, int to)
        {
            Edge_Count++;
            edge[Edge_Count].to = to;
            edge[Edge_Count].next = edge_list[from];
            edge_list[from] = Edge_Count;
            Edge_Count++;
            edge[Edge_Count].to = from;
            edge[Edge_Count].next = edge_list[to];
            edge_list[to] = Edge_Count;
        }
    };
    
    Edge_Type Graph;
    
    struct Segment_Tree_Type
    {
        
        struct Segment_Tree
        {
            int l;
            int r;
            int Mid;
            int Sum;
            int Ruri;
        };
        
        Segment_Tree tree[Max << 3];
        
        void Build (int l, int r, int now)
        {
            tree[now].l = l;
            tree[now].r = r;
            if (l == r)
                return ;
            tree[now].Mid = (l + r) >> 1;
            Build (l, tree[now].Mid, now << 1);
            Build (tree[now].Mid + 1, r, now << 1 | 1);
        }
        
        int Query_Section_Sum (int l, int r, int now)
        {
            if (tree[now].l == l && tree[now].r == r)
                return tree[now].Sum;
            if (tree[now].Ruri == 1)
            {
                tree[now << 1].Sum = tree[now << 1].r - tree[now << 1].l + 1;
                tree[now << 1].Ruri = 1;
                tree[now << 1 | 1].Sum = tree[now << 1 | 1].r - tree[now << 1 | 1].l + 1;
                tree[now << 1 | 1].Ruri = 1;
                tree[now].Ruri = 0;
            }
            else if (tree[now].Ruri == 2)
            {
                tree[now << 1].Sum = 0;
                tree[now << 1 | 1].Sum = 0;
                tree[now << 1].Ruri = 2;
                tree[now << 1 | 1].Ruri = 2;
                tree[now].Ruri = 0;
            }
            tree[now].Sum = tree[now << 1].Sum + tree[now << 1 | 1].Sum;    
            if (r <= tree[now].Mid)
                return Query_Section_Sum (l, r, now << 1);
            else if (l > tree[now].Mid)
                return Query_Section_Sum (l, r, now << 1 | 1);
            else 
                return Query_Section_Sum (l, tree[now].Mid, now << 1) + Query_Section_Sum (tree[now].Mid + 1, r, now << 1 | 1);
        }
        
        void Change_Section (int l, int r, int now, int to)
        {
            if (tree[now].l == l && tree[now].r == r)
            {
                if (to == 1)
                {
                    tree[now].Sum = tree[now].r - tree[now].l + 1;
                    tree[now].Ruri = 1;
                    return ;
                }
                else if (to == 2)
                {
                    tree[now].Sum = 0;
                    tree[now].Ruri = 2;
                    return ;
                }
            }
            if (tree[now].Ruri == 1)
            {
                tree[now << 1].Sum = tree[now << 1].r - tree[now << 1].l + 1;
                tree[now << 1].Ruri = 1;
                tree[now << 1 | 1].Sum = tree[now << 1 | 1].r - tree[now << 1 | 1].l + 1;
                tree[now << 1 | 1].Ruri = 1;
                tree[now].Ruri = 0;
            }
            else if (tree[now].Ruri == 2)
            {
                tree[now << 1].Sum = 0;
                tree[now << 1 | 1].Sum = 0;
                tree[now << 1].Ruri = 2;
                tree[now << 1 | 1].Ruri = 2;
                tree[now].Ruri = 0;
            }
            if (r <= tree[now].Mid)
                Change_Section (l, r, now << 1, to);
            else if (l > tree[now].Mid)
                Change_Section (l, r, now << 1 | 1, to);
            else
            {
                Change_Section (l, tree[now].Mid, now << 1, to);
                Change_Section (tree[now].Mid + 1, r, now << 1 | 1, to); 
            }
            tree[now].Sum = tree[now << 1].Sum + tree[now << 1 | 1].Sum;
        }
        
    };
    
    Segment_Tree_Type Tree;
    
    struct Tree_Chain_Get_Type
    {
        
        struct Point_Type
        {
            int size;
            int deep;
            int father;
            int chain_up_point;
            int tree_number;
            int end;
        };
        
        Point_Type point[Max];
        
        int Count;
        
        void Dfs_1 (int now, int father)
        {
            int pos = Count++;
            point[now].deep = point[father].deep + 1;
            point[now].father = father;
            for (int i = Graph.edge_list[now]; i; i = Graph.edge[i].next)
                if (Graph.edge[i].to != father)
                    Dfs_1 (Graph.edge[i].to, now);
            point[now].size = Count - pos;
        }
        
        void Dfs_2 (int now, int chain)
        {
            int pos = 0;
            point[now].chain_up_point = chain;
            point[now].tree_number = ++Count;
            for (int i = Graph.edge_list[now]; i; i = Graph.edge[i].next)
                if (!point[Graph.edge[i].to].tree_number && point[Graph.edge[i].to].size > point[pos].size)
                    pos = Graph.edge[i].to;
            if (pos)
                Dfs_2 (pos, chain);
            for (int i = Graph.edge_list[now]; i; i = Graph.edge[i].next)
                if (!point[Graph.edge[i].to].tree_number)
                    Dfs_2 (Graph.edge[i].to, Graph.edge[i].to);
            point[now].end = Count;    
        }
        
        void Chain_Change (int x, int y, int type)
        {
            while (point[x].chain_up_point != point[y].chain_up_point)
            {
                if (point[point[x].chain_up_point].deep < point[point[y].chain_up_point].deep)
                    swap (x, y);
                Tree.Change_Section (point[point[x].chain_up_point].tree_number, point[x].tree_number, 1, type); 
                x = point[point[x].chain_up_point].father;
            }
            Tree.Change_Section (min (point[x].tree_number, point[y].tree_number), max (point[x].tree_number, point[y].tree_number), 1, type);
            return ; 
        }
        
        int Chain_Query (int x, int y)
        {
            int Answer = 0;
            while (point[x].chain_up_point != point[y].chain_up_point)
            {
                if (point[point[x].chain_up_point].deep < point[point[y].chain_up_point].deep)
                    swap (x, y);
                Answer += Tree.Query_Section_Sum (point[point[x].chain_up_point].tree_number ,point[x].tree_number, 1); 
                x = point[point[x].chain_up_point].father;
            }
            Answer += Tree.Query_Section_Sum (min (point[x].tree_number, point[y].tree_number), max (point[x].tree_number, point[y].tree_number), 1);
            return Answer; 
        }
    };
    
    Tree_Chain_Get_Type Make;
    
    int N, M;
    
    int main (int argc, char *argv[])
    {
        read (N);
        int x;
        for (int i = 2; i <= N; i++)
        {
            read (x);
            x++;
            Graph.Add_Edge (i, x);
        }
        Make.Dfs_1 (1, 0);
        Make.Count = 0;
        Make.Dfs_2 (1, 1);
        Tree.Build (1, N, 1);
        read (N);
        char type[10];
        int now;
        while (N--)
        {
            scanf ("%s", type);
            read (x);
            x++;
            if (type[0] == 'i')
            {
                now = Make.Chain_Query (1, x); 
                Make.Chain_Change (1, x, 1); 
                printf ("%d
    ", Make.point[x].deep - now);
            }
            else
            {
                now = Tree.Query_Section_Sum (Make.point[x].tree_number, Make.point[x].end, 1);
                Tree.Change_Section (Make.point[x].tree_number, Make.point[x].end, 1, 2);
                printf ("%d
    ", now);
            }
        }
        return 0;
    }
  • 相关阅读:
    数据库基础
    (转)数据流图
    (转)SQL执行顺序
    (转)数据库隔离级别及实现原理
    (转)求单链表是否有环,环入口和环长
    (转)最长公共子序列
    (转)Java锁、自旋锁、CAS机制
    Java线程状态转换
    OpenSUSE 13.2安装Texlive2014+Texmaker+Lyx
    GIMP也疯狂之动态图的制作(四)
  • 原文地址:https://www.cnblogs.com/ZlycerQan/p/6822431.html
Copyright © 2011-2022 走看看