BZOJ 4034: [HAOI2015]树上操作

二次联通门 : BZOJ 4034: [HAOI2015]树上操作

 

 

 

/*
    BZOJ 4034: [HAOI2015]树上操作
    
    树剖 + 线段树维护 + Dfs序
    
    对于子树修改, 打个时间戳就好, 然后就可以直接改了
    
    单点修改只需对应着点的树上序号就可以直接线段树单点修改..
     
    链上直接查询 ..
        我也就只能做做这种水题了..
     
*/
#include <cstdio>

#define Max 200190

void read (long long &now)
{
    now = 0;
    register char word = getchar ();
    bool flag = false;
    while (word < '0' || word > '9')
    {
        if (word == '-')
            flag = true;
        word = getchar ();
    }
    while (word >= '0' && word <= '9')
    {
        now = now * 10 + word - '0';
        word = getchar ();
    }    
    if (flag)
        now = -now; 
}

inline long long min (long long a, long long b)
{
    return a < b ? a : b;
}

inline long long max (long long a, long long b)
{
    return a > b ? a : b;
}

inline long long swap (long long &a, long long &b)
{
    long long now = a; 
    a = b;
    b = now;
}

long long tree_dis[Max];
long long Cur;

class Segment_Tree_Type
{
    private :
        
        struct Segment_Tree
        {
            long long l;
            long long r;
            long long Mid;
            long long Sum;
            long long Ruri;
        }
        tree[Max << 3];
        
    public :
        
        void Build (long long l, long long r, long long now)
        {
            tree[now].l = l;
            tree[now].r = r;
            if (l == r)
            {
                tree[now].Sum = tree_dis[++Cur];
                return ;
            }
            tree[now].Mid = (l + r) >> 1;
            Build (l, tree[now].Mid, now << 1);
            Build (tree[now].Mid + 1, r, now << 1 | 1);
            tree[now].Sum = tree[now << 1].Sum + tree[now << 1 | 1].Sum;
        }
        
        void Change_single (long long pos, long long now, long long to)
        {
            if (tree[now].l == tree[now].r)
            {
                tree[now].Sum += to;
                return ;
            }
            if (tree[now].Ruri)
            {
                tree[now << 1].Sum += (tree[now << 1].r - tree[now << 1].l + 1) * tree[now].Ruri;
                tree[now << 1].Ruri += tree[now].Ruri;
                tree[now << 1 | 1].Sum += (tree[now << 1 | 1].r - tree[now << 1 | 1].l + 1) * tree[now].Ruri;
                tree[now << 1 | 1].Ruri += tree[now].Ruri;
                tree[now].Ruri = 0;
            }
            if (pos <= tree[now].Mid)
                Change_single (pos, now << 1, to);
            else if (pos > tree[now].Mid)
                Change_single (pos, now << 1 | 1, to);
            tree[now].Sum = tree[now << 1].Sum + tree[now << 1 | 1].Sum;
        }
        
        void Change_section (long long l, long long r, long long now, long long to)
        {
            if (tree[now].l == l && tree[now].r == r)
            {
                tree[now].Sum += (tree[now].r - tree[now].l + 1) * to;
                tree[now].Ruri += to;
                return ;
            }
            if (tree[now].Ruri)
            {
                tree[now << 1].Sum += (tree[now << 1].r - tree[now << 1].l + 1) * tree[now].Ruri;
                tree[now << 1].Ruri += tree[now].Ruri;
                tree[now << 1 | 1].Sum += (tree[now << 1 | 1].r - tree[now << 1 | 1].l + 1) * tree[now].Ruri;
                tree[now << 1 | 1].Ruri += tree[now].Ruri;
                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;
        }
        
        long long Query_section (long long l, long long r, long long now)
        {
            if (tree[now].l == l && tree[now].r == r)
                return tree[now].Sum;
            if (tree[now].Ruri)
            {
                tree[now << 1].Sum += (tree[now << 1].r - tree[now << 1].l + 1) * tree[now].Ruri;
                tree[now << 1].Ruri += tree[now].Ruri;
                tree[now << 1 | 1].Sum += (tree[now << 1 | 1].r - tree[now << 1 | 1].l + 1) * tree[now].Ruri;
                tree[now << 1 | 1].Ruri += tree[now].Ruri;
                tree[now].Ruri = 0;
            }
            tree[now].Sum = tree[now << 1].Sum + tree[now << 1 | 1].Sum;
            if (r <= tree[now].Mid)
                return Query_section (l, r, now << 1);
            else if (l > tree[now].Mid)
                return Query_section (l, r, now << 1 | 1);
            else 
                return Query_section (l, tree[now].Mid, now << 1) + Query_section (tree[now].Mid + 1, r, now << 1 | 1); 
        }
};

Segment_Tree_Type Tree;

struct Graph_Type
{
    
    struct Edges
    {
        long long to;
        long long next;
    }
    
    edge[Max << 3];
    long long edge_list[Max];
    long long Edge_Count;
    
    inline void Add_Edge (long long from, long long 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;
    }
};

Graph_Type Graph;

class Tree_Chain_Get_Type 
{
    private :
        
        struct Point_Type
        {
            long long deep;
            long long size;
            long long father;
            long long up_chain_point;
            long long end;
            long long dis;
            long long tree_number;
        }
        
        point[Max];
    
        long long Count;
            
    public :
 
        inline void Clear ()
        {
             Count = 0;
        }
        
        void Dfs_1 (long long now, long long father)
        {
            point[now].father = father;
            point[now].deep = point[father].deep + 1;
            long long pos = Count++;
            for (long long 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 (long long now, long long chain)
        {
            long long pos = 0;
            point[now].up_chain_point = chain;
            point[now].tree_number = ++Count;
            tree_dis[Count] = point[now].dis;
            for (long long 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)
            {
                point[now].end = Count;
                return ;
            }
            Dfs_2 (pos, chain);
            for (long long i = Graph.edge_list[now]; i; i = Graph.edge[i].next)
                if (Graph.edge[i].to != pos && !point[Graph.edge[i].to].tree_number)
                    Dfs_2 (Graph.edge[i].to, Graph.edge[i].to);
            point[now].end = Count;
        }
        
        long long Query_chain (long long x)
        {
            long long Answer = 0;
            while (point[x].up_chain_point)
            {
                Answer += Tree.Query_section (point[point[x].up_chain_point].tree_number, point[x].tree_number, 1);
                x = point[point[x].up_chain_point].father; 
            }
            return Answer;
        }
        
        long long Get_Point_number (long long now)
        {
            return point[now].tree_number;
        }
        
        void Key_in_point_dis (long long now, long long dis)
        {
            point[now].dis = dis;
        }
        
        long long Get_Point_End_number (long long now)
        {
            return point[now].end;
        }
};

Tree_Chain_Get_Type Make;

long long N, M;

int main (int argc, char *argv[])
{
    read (N);
    read (M);
    long long x, y;
    for (long long i = 1; i <= N; i++)
    {
        read (x);
        Make.Key_in_point_dis (i, x); 
    }
    for (long long i = 1; i < N; i++)
    {
        read (x);
        read (y);
        Graph.Add_Edge (x, y); 
    }
    Make.Dfs_1 (1, 0);
    Make.Clear ();
    Make.Dfs_2 (1, 1);
    Tree.Build (1, N, 1);
    while (M--)
    {
        read (x);
        if (x == 1)
        {
            read (x);
            read (y);
            Tree.Change_single (Make.Get_Point_number (x), 1, y);  
        }
        else if (x == 2)
        {
            read (x);
            read (y);
            Tree.Change_section (Make.Get_Point_number (x), Make.Get_Point_End_number (x), 1, y); 
        }
        else 
        {
            read (x);
            printf ("%lld\n", Make.Query_chain (x));
        }
    }
    return 0;
}

 

myj 吊打我Orz,xxy 捆起来打我Orz,myl 文化课上天Orz, lrh 姿势水平敲高Orz, hkd 特别胖Orz%%%,cys 智商感人Orz,syl zz专业Orz,我没有学上, 我们未来一片光明
posted @ 2017-05-13 11:10  ZlycerQan  阅读(228)  评论(0编辑  收藏  举报