COGS 1583. [POJ3237]树的维护

二次联通门 : COGS 1583. [POJ3237]树的维护

/*
    COGS 1583. [POJ3237]树的维护

    树链剖分 + 边权化点权
    线段树 单点修改 +  区间取相反数 + 查询区间最大

    对于区间取相反数
        考虑在线段树中维护两个值
        一个区间最大, 一个区间最小
        对于更改, 只需把区间最大与最小分别取相反数后交换即可

        然后对于标记, 由于对区间连续取反两次相当于不变
        则只需开一个bool 标记, 每次放标记时对标记取反即可

*/
#include <cstdio>

#define INF 1e7
#define Max 20005

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

inline int min (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;
    bool temp = false;
    register char word = getchar ();
    while (word < ‘0‘ || word > ‘9‘)
    {
        if (word == ‘-‘)
            temp = true;
        word = getchar ();
    }
    while (word <= ‘9‘ && word >= ‘0‘)
    {
        now = now * 10 + word - ‘0‘;
        word = getchar ();
    }
}

int tree_value[Max];

class Segment_Tree_Type
{
    private :

        struct Tree_Date
        {
            int l;
            int r;
            int Maxn;
            int Minn;
            int Mid;
            bool Flandre_Scarlet;
        }
        tree[Max << 3];

    public :

        void Build (int l, int r, int now)
        {
            tree[now].l = l;
            tree[now].r = r;
            if (l == r)
            {
                tree[now].Maxn = tree_value[l];
                tree[now].Minn = tree_value[r];
                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].Maxn = max (tree[now << 1].Maxn, tree[now << 1 | 1].Maxn);
            tree[now].Minn = min (tree[now << 1].Minn, tree[now << 1 | 1].Minn);
        }

        int Query_Section (int l, int r, int now)
        {
            if (tree[now].l == l && tree[now].r == r)
                return tree[now].Maxn;
            if (tree[now].Flandre_Scarlet)
            {
                tree[now << 1].Maxn = -tree[now << 1].Maxn;
                tree[now << 1 | 1].Maxn = -tree[now << 1 | 1].Maxn;
                tree[now << 1].Minn = -tree[now << 1].Minn;
                tree[now << 1 | 1].Minn = -tree[now << 1 | 1].Minn;
                swap (tree[now << 1].Maxn, tree[now << 1].Minn);
                tree[now << 1].Flandre_Scarlet = !tree[now << 1].Flandre_Scarlet;
                swap (tree[now << 1 | 1].Maxn, tree[now << 1 | 1].Minn);
                tree[now << 1 | 1].Flandre_Scarlet = !tree[now << 1 | 1].Flandre_Scarlet;
                tree[now].Flandre_Scarlet = false;
            }
            tree[now].Maxn = max (tree[now << 1].Maxn, tree[now << 1 | 1].Maxn);
            tree[now].Minn = min (tree[now << 1].Minn, tree[now << 1 | 1].Minn);
            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 max (Query_Section (l, tree[now].Mid, now << 1), Query_Section (tree[now].Mid + 1, r, now << 1 | 1));
        }

        void Change_Section (int l, int r, int now)
        {
            if (tree[now].l == l && tree[now].r == r)
            {
                tree[now].Maxn = -tree[now].Maxn;
                tree[now].Minn = -tree[now].Minn;
                swap (tree[now].Maxn, tree[now].Minn);
                tree[now].Flandre_Scarlet = !tree[now].Flandre_Scarlet;
                return ;
            }
            if (tree[now].Flandre_Scarlet)
            {
                tree[now << 1].Maxn = -tree[now << 1].Maxn;
                tree[now << 1 | 1].Maxn = -tree[now << 1 | 1].Maxn;
                tree[now << 1].Minn = -tree[now << 1].Minn;
                tree[now << 1 | 1].Minn = -tree[now << 1 | 1].Minn;
                swap (tree[now << 1].Maxn, tree[now << 1].Minn);
                tree[now << 1].Flandre_Scarlet = !tree[now << 1].Flandre_Scarlet;
                swap (tree[now << 1 | 1].Maxn, tree[now << 1 | 1].Minn);
                tree[now << 1 | 1].Flandre_Scarlet = !tree[now << 1 | 1].Flandre_Scarlet;
                tree[now].Flandre_Scarlet = false;
            }
            if (r <= tree[now].Mid)
                Change_Section (l, r, now << 1);
            else if (l > tree[now].Mid)
                Change_Section (l, r, now << 1 | 1);
            else
            {
                Change_Section (l, tree[now].Mid, now << 1);
                Change_Section (tree[now].Mid + 1, r, now << 1 | 1);
            }
            tree[now].Maxn = max (tree[now << 1].Maxn, tree[now << 1 | 1].Maxn);
            tree[now].Minn = min (tree[now << 1].Minn, tree[now << 1 | 1].Minn);
        }

        void Change_Single (int pos, int now, int number)
        {
            if (tree[now].l == tree[now].r)
            {
                tree[now].Maxn = number;
                tree[now].Minn = number;
                return;
            }
            if (tree[now].Flandre_Scarlet)
            {
                tree[now << 1].Maxn = -tree[now << 1].Maxn;
                tree[now << 1 | 1].Maxn = -tree[now << 1 | 1].Maxn;
                tree[now << 1].Minn = -tree[now << 1].Minn;
                tree[now << 1 | 1].Minn = -tree[now << 1 | 1].Minn;
                swap (tree[now << 1].Maxn, tree[now << 1].Minn);
                tree[now << 1].Flandre_Scarlet = !tree[now << 1].Flandre_Scarlet;
                swap (tree[now << 1 | 1].Maxn, tree[now << 1 | 1].Minn);
                tree[now << 1 | 1].Flandre_Scarlet = !tree[now << 1 | 1].Flandre_Scarlet;
                tree[now].Flandre_Scarlet = false;
            }
            if (pos <= tree[now].Mid)
                Change_Single (pos, now << 1, number);
            else
                Change_Single (pos, now << 1 | 1, number);
            tree[now].Maxn = max (tree[now << 1].Maxn, tree[now << 1 | 1].Maxn);
            tree[now].Minn = min (tree[now << 1].Minn, tree[now << 1 | 1].Minn);
        }
};

Segment_Tree_Type Segment_Tree;

class Tree_Chain_Type
{
    private :

        struct Edge_Date
        {
            int to;
            int next;
            int key;
            int from;
        }
        edge[Max << 2];

        struct Point_Date
        {
            int size;
            int father;
            int up_chain_point;
            int deep;
            int segment_tree_pos;
        }
        point[Max];

        int Edge_Count;
        int edge_list[Max];
        int Segment_Pos;
        int Count;

    public :

        inline int Add_Edge (int from, int to, int dis)
        {
            Edge_Count++;
            edge[Edge_Count].to = to;
            edge[Edge_Count].from = from;
            edge[Edge_Count].next = edge_list[from];
            edge_list[from] = Edge_Count;
            edge[Edge_Count].key = dis;
            Edge_Count++;
            edge[Edge_Count].to = from;
            edge[Edge_Count].from = to;
            edge[Edge_Count].next = edge_list[to];
            edge_list[to] = Edge_Count;
            edge[Edge_Count].key = dis;
        }

        void Dfs_1 (int now, int father)
        {
            int pos = Count++;
            point[now].father = father;
            point[now].deep = point[father].deep + 1;
            for (int i = edge_list[now]; i; i = edge[i].next)
                if (edge[i].to != father)
                    Dfs_1 (edge[i].to, now);
            point[now].size = Count - pos;
        }

        void Dfs_2 (int now, int chain)
        {
            point[now].segment_tree_pos = ++Segment_Pos;
            for (int i = edge_list[now]; i; i = edge[i].next)
                if (edge[i].to == point[now].father)
                {
                    tree_value[Segment_Pos] = edge[i].key;
                    break;
                }
            point[now].up_chain_point = chain;
            int pos = 0;
            for (int i = edge_list[now]; i; i = edge[i].next)
                if (!point[edge[i].to].segment_tree_pos && point[edge[i].to].size >  point[pos].size)
                    pos = edge[i].to;
            if (!pos)
                return;
            Dfs_2 (pos, chain);
            for (int i = edge_list[now]; i; i = edge[i].next)
                if (!point[edge[i].to].segment_tree_pos && edge[i].to != pos)
                    Dfs_2 (edge[i].to, edge[i].to);
        }

        int Query_chain (int x, int y)
        {
            int Answer = -INF;
            while (point[x].up_chain_point != point[y].up_chain_point)
            {
                if (point[point[x].up_chain_point].deep < point[point[y].up_chain_point].deep)
                    swap (x, y);
                Answer = max (Answer, Segment_Tree.Query_Section (point[point[x].up_chain_point].segment_tree_pos, point[x].segment_tree_pos, 1));
                x = point[point[x].up_chain_point].father;
            }
            if (point[x].deep > point[y].deep)
                swap (x, y);
            if (x != y)
                Answer = max (Answer, Segment_Tree.Query_Section (point[x].segment_tree_pos + 1, point[y].segment_tree_pos, 1));
            return Answer;
        }

        void Change_chain (int x, int y)
        {
            while (point[x].up_chain_point != point[y].up_chain_point)
            {
                if (point[point[x].up_chain_point].deep < point[point[y].up_chain_point].deep)
                    swap (x, y);
                Segment_Tree.Change_Section (point[point[x].up_chain_point].segment_tree_pos, point[x].segment_tree_pos, 1);
                x = point[point[x].up_chain_point].father;
            }
            if (point[x].deep > point[y].deep)
                swap (x, y);
            if (x != y)
                Segment_Tree.Change_Section (point[x].segment_tree_pos + 1, point[y].segment_tree_pos, 1);
        }

        void Change_Single (int x, int number)
        {
            x = (x << 1) - 1;
            int pos = point[edge[x].to].deep > point[edge[x].from].deep ? point[edge[x].to].segment_tree_pos : point[edge[x].from].segment_tree_pos;
            Segment_Tree.Change_Single (pos, 1, number);
            return ;
        }
};

Tree_Chain_Type Make;

int main (int argc, char *argv[])
{
    freopen ("maintaintree.in", "r", stdin);
    freopen ("maintaintree.out", "w", stdout);
    int N;
    read (N);
    int x, y, z;
    for (int i = 1; i < N; i++)
    {
        read (x);
        read (y);
        read (z);
        Make.Add_Edge (x, y, z);
    }
    Make.Dfs_1 (1, 0);
    Make.Dfs_2 (1, 1);
    Segment_Tree.Build (1, N, 1);
    char type[10];
    while (scanf ("%s", type) && type[0] != ‘D‘)
    {
        read (x);
        read (y);
        if (type[0] == ‘Q‘)
            printf ("%d\n", Make.Query_chain (x, y));
        else if (type[0] == ‘C‘)
            Make.Change_Single (x, y);
        else
            Make.Change_chain (x, y);
    }
    return 0;
}
时间: 2024-08-07 17:01:45

COGS 1583. [POJ3237]树的维护的相关文章

cogs1583. [POJ3237]树的维护

1583. [POJ3237]树的维护 http://www.cogs.pro/cogs/problem/problem.php?pid=1583 ★★★☆   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条

[POJ3237]树的维护

P1424 - [POJ3237]树的维护 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条边的权值改成v. NEGATE a b:将点a到点b路径上所有边的权值变成其相反数. QUERY a b:找出点a到点b路径上各边的最大权值. Input 第一行有一个整数N(N<=10000). 接下来N-1行每行有三个整数a,b,c,代表点a和点b之间

cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树

1583. [POJ 3237] 树的维护 ★★★★   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条边的权值改成v. NEGATE a b:将点a到点b路径上所有边的权值变成其相反数. QUERY a b

线段树可维护的基本信息

一.区间最值 1.单点替换: 1 const int M=100001; 2 LL a[M]; 3 LL MAX[M<<2]; 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 void update(int rt){ 7 MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]); 8 } 9 void build(int l,int r,int rt){ 10 if

线段树 --- (区间维护+逆推)

Buy Tickets Time Limit:4000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year was appro

hdu 1556 Color the ball(线段树区间维护+单点求值)

传送门:Color the ball Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 25511    Accepted Submission(s): 12393 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele

【BZOJ2653】middle,主席树(非权值线段树)维护区间01信息+二分答案

传送门 写在前面:虽然这是一道我再也不想写的题目,但很好很有价值 思路: cxlove大神: 要求中位数最大,首先二分中位数,然后判断可行不可行. 判断X可行不可行,对于区间内的数,凡是>=X的标为1,否则为-1.这样的话,求一次最大区间和 如果大于等于0,则说明可行. 这要求我们不能像之前那样建立权值线段树的主席树(区间即为权值)了,而是以权值为下标,维护区间[1,n]的信息,可能有点拗口,这里就理解是我们平常写的普通线段树好了,只是这里是n棵由于根的不同而信息不同的线段树 具体实现 对于题目

BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)

原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形成树形的结构.局域网中有一台特殊的计算机,称之为核心计算机.根据一些初步的研究,研究员们拟定了一个一共m步的实验.实验开始之前,核

CodeForces 587 E.Duff as a Queen 线段树动态维护区间线性基

https://codeforces.com/contest/587/problem/E 一个序列, 1区间异或操作 2查询区间子集异或种类数 题解 解题思路大同小异,都是利用异或的性质进行转化,std和很多网友用的都是差分的思想,用两棵线段树 第一棵维护差分序列上的线性基,第二棵维护原序列的异或区间和,两者同时进行修改 考虑两个序列 $(a,b)(d,e)$,按照std的想法,应该是维护$(0 \^ a,a \^ b)(0 \^ d,d \^ e)$ 然后合并首尾变成$(0 \^ a,a \^