爱爬山的小Z(树状数组求区间最值)

这篇博客讲述了如何利用树状数组来解决ACdream王国中小Z在不断变化的山脉中,寻找登山路径最小困难程度的问题。文章通过一个童话故事引入,详细解释了输入输出格式,并提供了一个错误的代码模板作为例子,强调了正确理解和调试模板的重要性。

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

Problem Description

从前有一座ACdream王国,这个王国被群山环绕,因此外面的人很少有人知道它的存在。
这个王国里,有一位很喜欢爬山的小伙子,小Z,他觉得在爬山的过程中,能够有一种征服自然的感觉。
小Z定义一条登山路径的困难程度,为整个路径中经过的山的高度的最大值。
然而ACdream王国是一个很神奇的王国,山的高度经常会改变,因此小Z不得不随时重新测量山的高度。
小Z疲惫于测量高度,所以没有精力考虑每条路径的困难程度了。所以想请你帮忙。
Input

多组数据,每组数据首先是一个整数N(N<=100000),表示围绕着ACdream王国的山的数量
接下来是N个整数,表示每一座山的高度hi,编号从1开始,注意第1座山和第N座山相邻。
接下来是一个整数Q(Q<=100000),表示小Z进行的操作
接下来是Q行,每行是三个整数a,b,c,如果a为0,则代表小Z重新测量第b座山,高度为c,(1<=b<=N,1<=c<=100000)
如果a为1,则代表小Z想知道从b到c的最小困难程度。(1<=b,c<=N)
Output

对于每一次小Z的询问,输出一个整数,表示路径上的最小困难程度。
Sample Input

6
1 10 2 20 3 30
3
1 1 5
0 6 3
1 1 5
Sample Output

20
3
Hint

故事是这样的,小Z养了一只兔子和一只乌龟,受到小Z的兴趣的影响,兔子和乌龟也喜欢爬山~
有一天,兔子和乌龟要比赛,规定从1号山作为起点,5号山作为终点
小Z说“预备,起~”后,聪明的兔子就沿着1-2-3-4-5的顺序拼命跑。
这是专业坑队友的小Z发现自己的地图的6号山的高度写错了,多写了一个0,赶紧改了~
然而这时兔子已经不知道去哪了,于是乌龟就慢条斯理地沿着1-6-5散步,最终乌龟获得胜利~!
《ACdream童话故事——龟兔赛跑》完

因为是一个环,所以顺时针,逆时针都可以走,然后求路线中的最大值,再取两条路线中的最小值。
之前队友说树状数组过不了,线段树可以过,我就纳闷了,这是显然不可能的。但是自己交了一发,wa了,然后检查是否手残,思路是否有问题,都没有……那就只有模板有问题了。
检查了一遍……发现

void change(int x, int y)
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        c[i] = y;
        for (int j = 1; j < lowbit(i); j <<= 1)
        {
            c[i] = max(c[i], c[i - j]);
        }

这个写的很奇怪,它的作用是把a[x]的值改为y,但是看到内循环那里,从i到n里每次都改成了y,那a[i]呢!!被你吃了?!然后改了c[i] = a[i];
立马A了,模板不能相信,必须手敲再理解,再调试,千锤百炼才可以。

void change(int x, int y)
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        c[i] = a[i];
        for (int j = 1; j < lowbit(i); j <<= 1)
        {
            c[i] = max(c[i], c[i - j]);
        }
    }
}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
int a[200005], c[200005], n, m;
int lowbit(int x)
{
    return x&(-x);
}
void init()
{
    for (int i = 1; i <= n; i++)
    {
        c[i] = a[i];
        for (int j = 1; j < lowbit(i); j <<= 1)
        {
            c[i] = max(c[i], c[i - j]);
        }
    }
}
void change(int x, int y)
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        c[i] = a[i];
        for (int j = 1; j < lowbit(i); j <<= 1)
        {
            c[i] = max(c[i], c[i - j]);
        }
    }
}
int query(int l, int r)
{
    int ans = a[r];
    while (1)
    {
        ans = max(ans, a[r]);
        if (l == r)break;
        for (r -= 1; r - l >= lowbit(r); r -= lowbit(r))
        {
            ans = max(ans, c[r]);
        }
    }
    return ans;
}
int main()
{
#ifdef LOCAL
    freopen("C:\\Users\\ΡΡ\\Desktop\\in.txt", "r", stdin);
    //freopen("C:\\Users\\ΡΡ\\Desktop\\out.txt","w",stdout);
#endif // LOCAL
    while (scanf("%d", &n) != EOF)
    {
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        init();
        int q;
        scanf("%d", &q);
        while (q--)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            if (x == 1)
            {
                if (y > z)swap(y, z);
                printf("%d\n", min(query(y, z), max(query(1, y), query(z, n))));
                /*for(int i = 1;i <= n;i++)
                cout<<c[i]<<" ";
                cout<<endl;*/
            }
            else
            {
                a[y] = z;
                change(y, z);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值