C#学习笔记:线段树

本文通过一个具体的RMQ问题实例,详细介绍了如何利用线段树高效地处理区间查询和更新操作。通过构建和维护线段树,可以实现O(logN)的时间复杂度进行查询和更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目1 : RMQ问题再临-线段树

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

上回说到:小Hi给小Ho出了这样一道问题:假设整个货架上从左到右摆放了N种商品,并且依次标号为1到N,每次小Hi都给出一段区间[L, R],小Ho要做的是选出标号在这个区间内的所有商品重量最轻的一种,并且告诉小Hi这个商品的重量。但是在这个过程中,可能会因为其他人的各种行为,对某些位置上的商品的重量产生改变(如更换了其他种类的商品)。

小Ho提出了两种非常简单的方法,但是都不能完美的解决。那么这一次,面对更大的数据规模,小Ho将如何是好呢?

提示:其实只是比ST少计算了一些区间而已

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第1行为一个整数N,意义如前文所述。

每组测试数据的第2行为N个整数,分别描述每种商品的重量,其中第i个整数表示标号为i的商品的重量weight_i。

每组测试数据的第3行为一个整数Q,表示小Hi总共询问的次数与商品的重量被更改的次数之和。

每组测试数据的第N+4~N+Q+3行,每行分别描述一次操作,每行的开头均为一个属于0或1的数字,分别表示该行描述一个询问和描述一次商品的重量的更改两种情况。对于第N+i+3行,如果该行描述一个询问,则接下来为两个整数Li, Ri,表示小Hi询问的一个区间[Li, Ri];如果该行描述一次商品的重量的更改,则接下来为两个整数Pi,Wi,表示位置编号为Pi的商品的重量变更为Wi

对于100%的数据,满足N<=10^6,Q<=10^6, 1<=Li<=Ri<=N,1<=Pi<=N, 0<weight_i, Wi<=10^4。

输出

对于每组测试数据,对于每个小Hi的询问,按照在输入中出现的顺序,各输出一行,表示查询的结果:标号在区间[Li, Ri]中的所有商品中重量最轻的商品的重量。

样例输入
10
3655 5246 8991 5933 7474 7603 6098 6654 2414 884 
6
0 4 9
0 2 10
1 4 7009
0 5 6
1 3 7949
1 3 1227
样例输出
2414
884
7474
详见:hihoCoder
     
     


按照提示写了实现方法,但是提交后超出时限,所以只得了90分。附代码:

using System;

namespace SegmentTree
{
    public class Program
    {
        static void Main()
        {
            int N = int.Parse(Console.ReadLine());
            int[] weights = new int[N];
            string[] inputs = Console.ReadLine().Split(' ');
            for (int i = 0; i < N; i++)
            {
                weights[i] = int.Parse(inputs[i]);
            }
            Tree t = new Tree(weights);
            N = int.Parse(Console.ReadLine());
            while (N-- > 0)
            {
                inputs = Console.ReadLine().Split(' ');
                switch (inputs[0])
                {
                    case "0":
                        Console.WriteLine(t.Search(int.Parse(inputs[1]), int.Parse(inputs[2])));
                        break;
                    case "1":
                        t.Change(int.Parse(inputs[1]), int.Parse(inputs[2]));
                        break;
                }
            }
        }
    }

    public class Tree
    {
        public class Node
        {
            public Node(int sidx, int eidx, int weight)
            {
                this.sidx = sidx;
                this.eidx = eidx;
                this.weight = weight;
            }

            int weight;
            int sidx;
            int eidx;

            Node parent;
            Node left;
            Node right;

            public int Weight { get { return weight; } set { weight = value; } }
            public int StartIndex { get { return sidx; } }
            public int EndIndex { get { return eidx; } }
            public Node Parent { get { return parent; } set { parent = value; } }
            public Node Left { get { return left; } set { left = value; } }
            public Node Right { get { return right; } set { right = value; } }

            public int Reset()
            {
                int result = this.weight;
                if (left != null)
                {
                    int temp = left.Reset();
                    if (temp < result) result = temp;
                }
                if (right != null)
                {
                    int temp = right.Reset();
                    if (temp < result) result = temp;
                }
                this.weight = result;
                return result;
            }
        }

        public Tree(int[] weights)
        {
            root = buildTree(1, weights.Length, weights);
            root.Reset();
        }

        private Node buildTree(int start, int end, int[] weights)
        {
            Node node = new Node(start, end, int.MaxValue);
            if (start < end)
            {
                int mid = (start + end) / 2;
                Node left = buildTree(start, mid, weights);
                left.Parent = node;
                node.Left = left;
                Node right = buildTree(mid + 1, end, weights);
                right.Parent = node;
                node.Right = right;
            }
            if (start == end)
            {
                node.Left = null;
                node.Right = null;
                node.Weight = weights[start - 1];
            }
            return node;
        }

        Node root;
        public Node Root { get { return root; } }

        public void Change(int index, int weight)
        {
            Node parent = root;
            do
            {
                int mid = (parent.StartIndex + parent.EndIndex) / 2;
                if (index <= mid) parent = parent.Left;
                else parent = parent.Right;
            } while (parent.StartIndex != index || parent.EndIndex != index);
            parent.Weight = weight;
            while (parent.Parent != null)
            {
                Node temp = parent.Parent;
                temp.Weight = temp.Left.Weight > temp.Right.Weight ? temp.Right.Weight : temp.Left.Weight;
                parent = temp;
            }
        }

        public int Search(int left, int right)
        {
            return search(root, left, right);
        }
        private int search(Node parent, int left, int right)
        {
            if (left == parent.StartIndex && right == parent.EndIndex)
            {
                return parent.Weight;
            }
            int mid = (parent.StartIndex + parent.EndIndex) / 2;
            if (right <= mid)
            {
                return search(parent.Left, left, right);
            }
            else if(left > mid)
            {
                return search(parent.Right, left, right);
            }
            else
            {
                int lw = search(parent.Left, left, mid);
                int rw = search(parent.Right, mid + 1, right);
                return lw > rw ? rw : lw;
            }
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值