Minimum(线段树)log(n)复杂度

题意:
输入2^n个数将这些数分为好多个区间,询问这个区间里的最小值,最小值为区间里的某个数与某个数相乘(可以相同),q次询问可以 输入1 代表求吃某个区间的某个值,2代表单点修改 区间里的某个点的值

思路:一开始用的是单调队列,以为能水过,没想到超时时间是O(n*m)的复杂度会超时,还是得用log(n)的复杂度,线段树才能过
其实学了线段树,单调队列基本上就不用学了,但单调队列也是一种简单的代码,线段树能解决好多问题,包括二分的思想的题

WA 代码:

#include<bits/stdc++.h>
using namespace std;
//单调队列
int k=3,n;
int q1[150000],q2[150000];
int a[150000];
int slove_min(int l,int r)
{
    int head=l,tail=l-1;
    for(int i=l; i<r; i++)
    {
        while(head<=tail&&a[q1[tail]]>a[i])//最小元素更新到队首
            tail--;
        q1[++tail]=i;
    }
    return a[head];
}
int slove_max(int l,int r)
{
    int head=l,tail=l-1;
    for(int i=l; i<r; i++)
    {
        while(head<=tail&&a[q2[tail]]<a[i])//最大元素更新到队首
            tail--;
        q2[++tail]=i;
    }
    return a[head];
}
int main()
{
    int t;
   scanf("%d",&t);
    while(t--)
    {
        int n,k;
    scanf("%d",&k);
        n=(int)pow(2,k);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
            //printf("%d",slove_min(0,7));
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int judge,r,l,maxx,minx;
            scanf("%d %d %d",&judge,&l,&r);
            if(judge==1)
            {
                maxx=slove_max(l,r);
                minx=slove_min(l,r);
                if(minx>=0)
                 printf("%d\n",minx*minx);
                else if(maxx<=0)
                    printf("%d\n",maxx*maxx);
                else if(maxx>0&&minx<0)
                    printf("%d\n",maxx*minx);
            }
            else
            {
                a[l]=r;
            }
        }

    }
}

AC代码:

#include<bits/stdc++.h>
using namespace std;
//线段树
#define N 150000
#define ll long long
ll a[N];
struct node
{
    ll l,r,maxx,minx;
}tree[4*N+10];
void update(ll k)
{
    tree[k].maxx=max(tree[k*2+1].maxx,tree[k*2].maxx);
    tree[k].minx=min(tree[k*2+1].minx,tree[k*2].minx);
}
void build(ll k,ll l,ll r)
{
    tree[k].l=l,tree[k].r=r;
    if(l==r)
    {
        tree[k].maxx=a[l];
        tree[k].minx=a[l];
        return ;
    }
    ll mid=(l+r)/2;
    build(k*2,l,mid);//左孩子
    build(k*2+1,mid+1,r);//右孩子
    update(k);
}
void change(ll k,ll x,ll y)
{
    if(tree[k].l==tree[k].r)
    {
        tree[k].maxx=y;
        tree[k].minx=y;
        return ;
    }
    ll mid=(tree[k].l+tree[k].r)/2;
    if(mid>=x)
    change(k*2,x,y);//在左区间
    else
    change(k*2+1,x,y);//在右区间
    update(k);
}
ll query_max(ll k,ll l,ll r)
{
    if(tree[k].l>=l&&tree[k].r<=r)
    {
        return tree[k].maxx;
    }
    ll mid=(tree[k].l+tree[k].r)/2;
    if(mid>=r)
       return query_max(k*2,l,r);
    if(mid<l)
       return query_max(k*2+1,l,r);
    return max(query_max(k*2,l,r),query_max(k*2+1,l,r));
}
ll query_min(ll k,ll l,ll r)
{
    if(tree[k].l>=l&&tree[k].r<=r)
    {
        return tree[k].minx;
    }
    ll mid=(tree[k].l+tree[k].r)/2;
    if(mid>=r)
       return query_min(k*2,l,r);
    if(mid<l)
       return query_min(k*2+1,l,r);
    return min(query_min(k*2,l,r),query_min(k*2+1,l,r));
}
int main()
{
     ll t;
   scanf("%lld",&t);
    while(t--)
    {
        ll n,k;
    scanf("%lld",&k);
        n=(ll)pow(2,k);
        for(ll i=1;i<=n;i++)
            scanf("%lld",&a[i]);
            //printf("%d",slove_min(0,7));
            build(1,1,n);
        ll q;
        scanf("%lld",&q);

        while(q--)
        {
            ll judge,r,l,maxx,minx;
            scanf("%lld %lld %lld",&judge,&l,&r);
            if(judge==1)
            {
                maxx=query_max(1,l+1,r+1);
                minx=query_min(1,l+1,r+1);
                if(minx>0)
                 printf("%lld\n",minx*minx);
                else if(maxx>0)
                    printf("%lld\n",maxx*minx);
                else
                    printf("%lld\n",maxx*maxx);
            }
            else
            {
               change(1,l+1,r);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值