XTU1238:Segment Tree(线段树区间更新)

本文介绍了一种使用线段树进行区间更新和区间查询的技术。具体包括四种操作:区间加法更新、区间最小值更新、区间最大值更新及查询区间内的最小值和最大值。通过实际代码示例展示了如何实现这些功能,并对初始错误代码进行了分析,指出并修正了存在的问题。

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

Segment Tree

   
Accepted : 98 Submit : 545
Time Limit : 9000 MS Memory Limit : 65536 KB

Segment Tree

Problem Description:

A contest is not integrity without problems about data structure.

There is an array a[1],a[2],…,a[n]. And q questions of the following 4 types:
  • 1 l r c - Update a[k] with a[k]+c for all l≤k≤r
  • 2 l r c - Update a[k] with min{a[k],c} for all l≤k≤r;
  • 3 l r c - Update a[k] with max{a[k],c} for all l≤k≤r;
  • 4 l r - Ask for min{a[k]:l≤k≤r} and max{a[k]:l≤k≤r}.

Input

The first line contains a integer T(no more than 5) which represents the number of test cases.

For each test case, the first line contains 2 integers n,q (1≤n,q≤200000).

The second line contains n integers a1,a2,…,an which indicates the initial values of the array (|ai|≤).

Each of the following q lines contains an integer t which denotes the type of i-th question. If t=1,2,3, 3 integers l,r,c follows. If t=4, 2 integers l,r follows. (1≤ti≤4,1≤li≤ri≤n)

If t=1, |ci|≤2000;

If t=2,3, |ci|≤10^9.

Output

For each question of type 4, output two integers denote the minimum and the maximum.

Sample Input

1
1 1
1
4 1 1

Sample Output

1 1


题目链接:http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1238

题目大意:自己看;

题目分析:线段树区间更新,区间求值;

我的初始错误代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=222222;
ll minv[maxn*8],maxv[maxn*8],num[maxn*8],smin[maxn*8],smax[maxn*8],addv[maxn*8];
int n,p;
ll _maxv,_minv;
void maintain(int o,int l,int r)
{
    int lc=o<<1,rc=o<<1|1;
    if(l==r)
        return ;
    minv[o]=min(minv[lc],minv[rc]);
    maxv[o]=max(maxv[lc],maxv[rc]);
}
void build(int o,int l,int r)
{
    int lc=o<<1,rc=o<<1|1;
    if(l==r)
    {
        minv[o]=maxv[o]=num[l];
        return ;
    }
    int m=(l+r)>>1;
    build(lc,l,m);
    build(rc,m+1,r);
    maintain(o,l,r);
}
void pushdown(int o,int l,int r)
{
    if(l==r)
        return ;
    int lc=o<<1,rc=o<<1|1;
    if(addv[o])
    {
        minv[lc]+=addv[o];
        minv[rc]+=addv[o];
        addv[lc]+=addv[o];
        addv[rc]+=addv[o];
        maxv[lc]+=addv[o];
        maxv[rc]+=addv[o];
        addv[o]=0;
    }
    if(smax[o])
    {
        smax[lc]=smax[rc]=smax[o];
        minv[lc]=max(minv[lc],smax[o]); minv[rc]=max(minv[rc],smax[o]);
        maxv[rc]=max(maxv[rc],smax[o]); maxv[lc]=max(maxv[lc],smax[o]);
        smax[o]=0;
    }
    if(smin[o])
    {
        smin[lc]=smin[rc]=smin[o];
        minv[lc]=min(minv[lc],smin[o]);  minv[rc]=min(minv[rc],smin[o]);
        maxv[rc]=min(maxv[rc],smin[o]);  maxv[lc]=min(maxv[lc],smin[o]);
        smin[o]=0;
    }
}
void unreduce(int o,int l,int r,int L,int R,ll c)
{
    int m=(l+r)>>1;
    int lc=o<<1,rc=o<<1|1;
    pushdown(o,l,r);
    if(l>=L&&r<=R)
    {
        smax[o]=c;
        minv[o]=max(minv[o],c);
        maxv[o]=max(maxv[o],c);
        return ;
    }
    if(L<=m)
        unreduce(lc,l,m,L,R,c);
    if(R>m)
        unreduce(rc,m+1,r,L,R,c);
    maintain(o,l,r);
}
void reduce(int o,int l,int r,int L,int R,ll c)
{
    int m=(l+r)>>1;
    int lc=o<<1,rc=o<<1|1;
    pushdown(o,l,r);
    if(l>=L&&r<=R)
    {
        smin[o]=c;
        minv[o]=min(minv[o],c);
        maxv[o]=min(maxv[o],c);
        return ;
    }
    if(L<=m)
        reduce(lc,l,m,L,R,c);
    if(R>m)
        reduce(rc,m+1,r,L,R,c);
    maintain(o,l,r);
}
void add(int o,int l,int r,int L,int R,ll c)
{
    int m=(l+r)>>1;
    int lc=o<<1,rc=o<<1|1;
     pushdown(o,l,r);
    if(l>=L&&r<=R)
    {
        addv[o]+=c;
        minv[o]+=c;
        maxv[o]+=c;
        return ;
    }
    if(L<=m)
        add(lc,l,m,L,R,c);
    if(R>m)
        add(rc,m+1,r,L,R,c);
    maintain(o,l,r);
}
void query(int o,int l,int r,int L,int R)
{
    int m=(l+r)>>1;
    int lc=o<<1,rc=o<<1|1;
    pushdown(o,l,r);
    if(l>=L&&r<=R)
    {
        _minv=min(_minv,minv[o]);
        _maxv=max(_maxv,maxv[o]);
        return ;
    }
    if(L<=m)
        query(lc,l,m,L,R);
    if(R>m)
        query(rc,m+1,r,L,R);
    maintain(o,l,r);
}
int main()
{
    int T;
    while(scanf("%d",&T)!=EOF)
    while(T--)
    {
        memset(addv,0,sizeof(addv));
        memset(smin,0,sizeof(smin));
        memset(smax,0,sizeof(smax));
        scanf("%d%d",&n,&p);
        for(int i=1;i<=n;i++)
        {
             scanf("%I64d",&num[i]);
        }
        build(1,1,n);
        int l,r;
        ll c;
        for(int i=0;i<p;i++)
        {
            int t;
            scanf("%d%d%d",&t,&l,&r);
            if(t==4)
            {
                _minv=1e12+7;
                _maxv=-1e12+7;
                query(1,1,n,l,r);
                printf("%I64d %I64d\n",_minv,_maxv);
                continue;
            }
            scanf("%I64d",&c);
            if(t==1)
            {
                add(1,1,n,l,r,c);
            }
            if(t==2)
            {
                reduce(1,1,n,l,r,c);
            }
            if(t==3)
            {
                unreduce(1,1,n,l,r,c);
            }
        }
    }
    return 0;
}

这份代码错误的地方有:

    当操作2,3时,有覆盖操作;

  比如有smax[lr]本身有值的时候,再赋予smax[lc]值时会产生覆盖,造成错误;

参考修改代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=222222;
ll minv[maxn*8],maxv[maxn*8],num[maxn*8],addv[maxn*8];
int n,p;
ll _maxv,_minv;
void maintain(int o,int l,int r)
{
    int lc=o<<1,rc=o<<1|1;
    if(l==r)
        return ;
    minv[o]=min(minv[lc],minv[rc]);
    maxv[o]=max(maxv[lc],maxv[rc]);
}
void build(int o,int l,int r)
{
    int lc=o<<1,rc=o<<1|1;
    if(l==r)
    {
        minv[o]=maxv[o]=num[l];
        return ;
    }
    int m=(l+r)>>1;
    build(lc,l,m);
    build(rc,m+1,r);
    maintain(o,l,r);
}
void pushdown(int o,int l,int r)
{
    int lc=o<<1,rc=lc+1;
    if(addv[o])
    {
        minv[lc]+=addv[o];
        minv[rc]+=addv[o];
        addv[lc]+=addv[o];
        addv[rc]+=addv[o];
        maxv[lc]+=addv[o];
        maxv[rc]+=addv[o];
        addv[o]=0;
    }
    minv[lc]=max(minv[o],minv[lc]);minv[lc]=min(maxv[o],minv[lc]);
    maxv[lc]=min(maxv[o],maxv[lc]);maxv[lc]=max(minv[o],maxv[lc]);


    maxv[rc]=min(maxv[o],maxv[rc]);maxv[rc]=max(minv[o],maxv[rc]);
    minv[rc]=max(minv[o],minv[rc]);minv[rc]=min(maxv[o],minv[rc]);
}
void unreduce(int o,int l,int r,int L,int R,ll c)
{
    int m=(l+r)>>1;
    int lc=o<<1,rc=o<<1|1;
    if(l>=L&&r<=R)
    {
        maxv[o]=max(maxv[o],c);
        minv[o]=max(minv[o],c);
        return ;
    }
    pushdown(o,l,r);
    if(L<=m)
        unreduce(lc,l,m,L,R,c);
    if(R>m)
        unreduce(rc,m+1,r,L,R,c);
    maintain(o,l,r);
}
void reduce(int o,int l,int r,int L,int R,ll c)
{
    int m=(l+r)>>1;
    int lc=o<<1,rc=o<<1|1;
    if(l>=L&&r<=R)
    {
        minv[o]=min(minv[o],c);
        maxv[o]=min(maxv[o],c);
        return ;
    }
    pushdown(o,l,r);
    if(L<=m)
        reduce(lc,l,m,L,R,c);
    if(R>m)
        reduce(rc,m+1,r,L,R,c);
    maintain(o,l,r);
}
void add(int o,int l,int r,int L,int R,ll c)
{
    int m=(l+r)>>1;
    int lc=o<<1,rc=o<<1|1;
    if(l>=L&&r<=R)
    {
        addv[o]+=c;
        minv[o]+=c;
        maxv[o]+=c;
        return ;
    }
    pushdown(o,l,r);
    if(L<=m)
        add(lc,l,m,L,R,c);
    if(R>m)
        add(rc,m+1,r,L,R,c);
    maintain(o,l,r);
}
void query(int o,int l,int r,int L,int R)
{
    int m=(l+r)>>1;
    int lc=o<<1,rc=o<<1|1;
    if(l>=L&&r<=R)
    {
        _minv=min(_minv,minv[o]);
        _maxv=max(_maxv,maxv[o]);
        return ;
    }
    pushdown(o,l,r);
    if(L<=m)
        query(lc,l,m,L,R);
    if(R>m)
        query(rc,m+1,r,L,R);
    maintain(o,l,r);
}
int main()
{
    int T;
    while(scanf("%d",&T)!=EOF)
    while(T--)
    {
        memset(addv,0,sizeof(addv));
        scanf("%d%d",&n,&p);
        for(int i=1;i<=n;i++)
        {
             scanf("%I64d",&num[i]);
        }
        build(1,1,n);
        int l,r;
        ll c;
        for(int i=0;i<p;i++)
        {
            int t;
            scanf("%d%d%d",&t,&l,&r);
            if(t==4)
            {
                _minv=1e12+7;
                _maxv=-1e12+7;
                query(1,1,n,l,r);
                printf("%I64d %I64d\n",_minv,_maxv);
                continue;
            }
            scanf("%I64d",&c);
            if(t==1)
            {
                add(1,1,n,l,r,c);
            }
            if(t==2)
            {
                reduce(1,1,n,l,r,c);
            }
            if(t==3)
            {
               unreduce(1,1,n,l,r,c);
            }
        }
    }dai
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值