线段树小结(基础题目)

基础题目套模版就是了

一:Description

为了检验你上午有没有好好听我讲课,于是有了这一题。给你一个数组a[1]~a[N],有q次操作,每次操作有两种类型,第一种询问操作,询问区间[l, r]之间数的和,第二种操作是修改操作,将位置loc的数改为x。对,你没有听错,就是这么简单,简单的话就赶快ac吧。

Input

第一行一个整数T,代表测试数据的组数.
接下来T组测试数据.
每组测试数据第一行两个整数N, q(N, q <= 1e5),分别代表数组a的长度和操作的个数
接下来一行为N个整数,代表数组a
接下来q行,每一行格式为下面两种格式中的一种
1 loc x 将loc位置的数改为x,即a[loc] = x(1 <= loc <= N, 1 <= x <= 1e5)
2 l, r 询问区间[l, r]之间数的和(1 <= l <= r <= N)

http://acm.hzau.edu.cn/problem.php?cid=1118&pid=2

分析:区间信息为sum,所以维护的信息是sum,划线部分之外的都是模版,划线部分(维护信息sum)可根据题意替换,模版不要动;

#include<bits/stdc++.h>
#include<set>
#include<iostream>
using namespace std;
#define maxn 100005
int a[maxn];
struct Node
{
    int L;
    int R;
    int sum;
}Node[maxn<<2];
int query(int i, int l, int r)
{

    if(Node[i].L == l && Node[i].R == r)
    {
        return Node[i].sum;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(r <= mid) return query(i<<1, l, r);
    else if(l > mid) return query((i<<1)|1, l, r);
    else
    {
        return query(i<<1, l, mid) + query((i<<1)|1, mid + 1, r);
    }
}//调用qury(1,l,r)即可查询[l,r]区间内元素的总和
void pushUp(int i)
{
    int lson = i<<1;
    int rson = lson + 1;
    Node[i].sum = Node[lson].sum + Node[rson].sum;
}
void update(int i, int loc, int value)
{
    if(Node[i].L == Node[i].R)
    {
        Node[i].sum = value;
        return;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(loc <= mid) update(i<<1, loc, value);
    else update((i<<1)|1, loc, value);
    pushUp(i);
}//若更新a[loc]的值为value,调用upd(1,loc,value)即可


void build(int i, int l, int r)
{
    Node[i].L = l;
    Node[i].R = r;
    Node[i].sum = 0;
    if(l == r)
    {
        Node[i].sum = a[l];
        return;
    }
    int mid = (l + r)>>1;
    build(i<<1, l, mid);
    build((i<<1)|1, mid + 1, r);
    pushUp(i);
}//如果原数组从a[1]~a[n],调用build(1,1,n)即可

int main()
{
    int T,N,q;
    int op,l,r,loc1,val1;
    cin>>T;
    for(int i=0;i<T;i++)
    {
        cin>>N>>q;
        for(int j=1;j<=N;j++)
        {
            cin>>a[j];
        }
        build(1,1,N);
        for(int k=0;k<q;k++)
        {
            cin>>op;
            if(op==1)
            {
                cin>>loc1>>val1;
                update(1,loc1,val1);
            }
            if(op==2)
            {
                cin>>l>>r;
                cout<<query(1,l,r)<<endl;
            }
        }
    }
    return 0;
}

#include<bits/stdc++.h>
#include<set>
#include<iostream>
using namespace std;
#define maxn 100005
int a[maxn];
struct Node
{
    int L;
    int R;
    int sum;
}Node[maxn<<2];
int query(int i, int l, int r)
{
 
    if(Node[i].L == l && Node[i].R == r)
    {
        return Node[i].sum;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(r <= mid) return query(i<<1, l, r);
    else if(l > mid) return query((i<<1)|1, l, r);
    else
    {
        return query(i<<1, l, mid) + query((i<<1)|1, mid + 1, r);
    }
}//调用qury(1,l,r)即可查询[l,r]区间内元素的总和
void pushUp(int i)
{
    int lson = i<<1;
    int rson = lson + 1;
    Node[i].sum = Node[lson].sum + Node[rson].sum;
}
void update(int i, int loc, int value)
{
    if(Node[i].L == Node[i].R)
    {
        Node[i].sum = value;
        return;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(loc <= mid) update(i<<1, loc, value);
    else update((i<<1)|1, loc, value);
    pushUp(i);
}//若更新a[loc]的值为value,调用upd(1,loc,value)即可
 
 
void build(int i, int l, int r)
{
    Node[i].L = l;
    Node[i].R = r;
    Node[i].sum = 0;
    if(l == r)
    {
        Node[i].sum = a[l];
        return;
    }
    int mid = (l + r)>>1;
    build(i<<1, l, mid);
    build((i<<1)|1, mid + 1, r);
    pushUp(i);
}//如果原数组从a[1]~a[n],调用build(1,1,n)即可
 
int main()
{
    int T,N,q;
    int op,l,r,loc1,val1;
    cin>>T;
    for(int i=0;i<T;i++)
    {
        cin>>N>>q;
        for(int j=1;j<=N;j++)
        {
            cin>>a[j];
        }
        build(1,1,N);
        for(int k=0;k<q;k++)
        {
            cin>>op;
            if(op==1)
            {
                cin>>loc1>>val1;
                update(1,loc1,val1);
            }
            if(op==2)
            {
                cin>>l>>r;
                cout<<query(1,l,r)<<endl;
            }
        }
    }
    return 0;
}

二:

Problem B: averyboy与社团

Time Limit: 2 Sec  Memory Limit: 128 MB
Submit: 79  Solved: 24
[Submit][Status][Web Board]

Description

又到了社团招新的时候,荟园主干道上有很多社团在摆点,averyboy来到了这里,在averyboy心中每个社团有一个满意度。我们可以想象这些社团招新点排成一排,编号从1-N,averyboy又定义了一个区间[l, r]的价值为在这段区间中所有社团满意度的最大值Max和最小值Min的差值即Max - Min.现在averyboy给了你一个问题。一共有q次操作,每次操作有两种类型,第一种类型为查询操作,查询区间[l, r]之间的价值。第二种是更改操作,将第i个社团招新点的满意度更改为x.

 

Input

第一行一个整数T,代表测试数据组数
接下来T组测试数据,每组测试数据第一行为两个整数N,q(N, q <= 1e5)分别代表社团招新点的个数和操作的个数
接下来一行有N个数,代表N个社团招新点的初始满意度
接下来q行,每一行格式如下面两种中的一种
1 loc x 代表更改操作,将第loc号社团招新点的满意度改为x(1 <= loc <= N, 1 <= x <= 1e5)
2 l r 代表查询操作,查询区间[l, r]的价值(l 1 <= l <= r <= N)

 

Output

对于每组数据的查询操作,输出结果.

Sample Input

1
5 3
1 2 3 4 5
2 1 5
1 1 2
2 1 5

Sample Output

4
3

http://acm.hzau.edu.cn/problem.php?cid=1118&pid=1

分析:维护区间信息由sum变为最大值和最小值(两个),还是套模版,把sum替换为最大最小值就好了。

#include<bits/stdc++.h>
#include<set>
#include<iostream>
using namespace std;
const int maxn=100005;
const int inf = 0x3f3f3f3f;
int a[maxn];
int Max,Min;
struct node
{
    int L;
    int R;
    int Min,Max;
}Node[maxn<<2];
void pushUp(int i)
{
    int lson = i<<1;
    int rson = lson + 1;
    Node[i].Max = max(Node[lson].Max, Node[rson].Max) ;
    Node[i].Min = min(Node[lson].Min, Node[rson].Min) ;
}
void build(int i, int l, int r)
{
    Node[i].L = l;
    Node[i].R = r;
    Node[i].Max=-1;
    Node[i].Min=inf;
    if(l == r)
    {
        Node[i].Max =  a[l];
        Node[i].Min =  a[l];
        return;
    }
    int mid = (l + r)>>1;
    build(i<<1, l, mid);
    build((i<<1)|1, mid + 1, r);
    pushUp(i);
}//如果原数组从a[1]~a[n],调用build(1,1,n)即可
void update(int i, int loc, int value)
{
    if(Node[i].L == Node[i].R)
    {
        Node[i].Max = value;
        Node[i].Min = value;
        return;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(loc <= mid) update(i<<1, loc, value);
    else update((i<<1)|1, loc, value);
    pushUp(i);
}//若更新a[loc]的值为value,调用upd(1,loc,value)即可
void query(int i,int l ,int r) //区间查询
{
	if(Node[i].L == l && Node[i].R == r)
    {
        Max=max(Max,Node[i].Max);
        Min=min(Min,Node[i].Min);
        return;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(r <= mid)  query(i<<1, l, r);
    else if(l > mid)  query((i<<1)|1, l, r);
    else
    {
        query(i<<1, l, mid);
        query((i<<1)|1, mid + 1, r);
    }
}
int N;
int main()
{
    int T,q;
    int op,l,r,loc1,val1;
    cin>>T;
    for(int i=0;i<T;i++)
    {
        cin>>N>>q;
        for(int j=1;j<=N;j++)
        {
            cin>>a[j];
        }
        build(1,1,N);
        for(int k=0;k<q;k++)
        {
            cin>>op;
            if(op==1)
            {
                cin>>loc1>>val1;
                update(1,loc1,val1);
            }
            if(op==2)
            {
                Max = -1;
                Min = inf;
                cin>>l>>r;
                query(1,l,r);
                cout<<Max-Min<<endl;
            }
        }
    }
    return 0;
}

三:

Problem D: averyboy的午餐2

Time Limit: 2 Sec  Memory Limit: 128 MB
Submit: 76  Solved: 28
[Submit][Status][Web Board]

Description

因为聪明的你帮averyboy解决了荟园阿姨给他的问题,他顺利获得了免费的午餐。这次,averyboy再次来到了荟园,还是那个窗口,还是那位阿姨。。。。。。这次,阿姨不想那么容易让他吃到免费的午餐,所以给出了比上次要难的问题。这不,averyboy又来 求助你了。阿姨这次给出的问题如下.给你一个数组a[1]~a[N],然后给你q次操作,每次操作有三种类型,第一种类型是把数组中的某一个数改为x,第二种操作是询问区间[l, r]之间所有奇数的和,如果这个区间没有奇数,输出0,第三种操作是询问区间[l, r]之间所有偶数的和,如果这个区间没有偶数,输出0.

Input

第一行一个整数T,代表测试数据的组数.
接下来T组测试数据.
每组测试数据第一行两个整数N, q(N, q <= 1e5),分别代表数组a的长度和操作的个数
接下来一行为N个整数,代表数组a
接下来q行,每一行格式为下面三种格式中的一种
1 loc x 将loc位置的数改为x,即a[loc] = x(1 <= loc <= N, 1 <= x <= 1e5)
2 l r 询问区间[l, r]之间奇数的和(1 <= l <= r <= N)
3 l r 询问区间[l, r]之间偶数的和(1 <= l <= r <= N)

 

Output

对于每组测试数据的询问操作,输出结果

Sample Input

1
5 4
1 2 3 4 5
2 1 5
3 1 5
1 1 2
3 1 5

Sample Output

9
6
8

分析:维护区间信息变为奇数和偶数和,注意相加数据范long long。

#include<bits/stdc++.h>
#include<set>
#include<iostream>
using namespace std;
typedef long long LL;
#define maxn 100005
LL a[maxn];
struct Node
{
    int L;
    int R;
    LL sum1,sum2;
}Node[maxn<<2];
LL query(int i, int l, int r,int type)
{

    if(Node[i].L == l && Node[i].R == r)
    {
        if(type==1)return Node[i].sum1;
        else return Node[i].sum2;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(r <= mid) return query(i<<1, l, r,type);
    else if(l > mid) return query((i<<1)|1, l, r,type);
    else


    {
         return query(i<<1, l, mid,type) + query((i<<1)|1, mid + 1, r,type);
    }
}//调用qury(1,l,r)即可查询[l,r]区间内元素的总和
void pushUp(int i)
{
    int lson = i<<1;
    int rson = lson + 1;
    Node[i].sum1 = Node[lson].sum1 + Node[rson].sum1;
    Node[i].sum2 = Node[lson].sum2 + Node[rson].sum2;
}
void update(int i, int loc, LL value)
{
    if(Node[i].L == Node[i].R)
    {
        if(value%2==1)
        {
           Node[i].sum1 = value;
           Node[i].sum2 = 0;
        }
        else
        {
            Node[i].sum1 = 0;
            Node[i].sum2 = value;
        }
        return;
    }
    int mid = (Node[i].L + Node[i].R)>>1;
    if(loc <= mid) update(i<<1, loc, value);
    else update((i<<1)|1, loc, value);
    pushUp(i);
}//若更新a[loc]的值为value,调用upd(1,loc,value)即可


void build(int i, int l, int r)
{
    Node[i].L = l;
    Node[i].R = r;
    Node[i].sum1 = 0;
    Node[i].sum2 = 0;
    if(l == r)
    {
        if(a[l]%2==1)
        {
           Node[i].sum1 = a[l];
        }
        else
        {
            Node[i].sum2 = a[l];
        }
        return;
    }
    int mid = (l + r)>>1;
    build(i<<1, l, mid);
    build((i<<1)|1, mid + 1, r);
    pushUp(i);
}//如果原数组从a[1]~a[n],调用build(1,1,n)即可

int main()
{
    int T,N,q;
    int op,l,r,loc1;
    LL val1;
    cin>>T;
    for(int i=0;i<T;i++)
    {
        cin>>N>>q;
        for(int j=1;j<=N;j++)
        {
            cin>>a[j];
        }
        build(1,1,N);
        for(int k=0;k<q;k++)
        {
            cin>>op;
            if(op==1)
            {
                cin>>loc1>>val1;
                update(1,loc1,val1);
            }
            if(op==2)
            {
                cin>>l>>r;
                cout<<query(1,l,r,1)<<endl;
            }
            if(op==3)
            {
                cin>>l>>r;
                cout<<query(1,l,r,2)<<endl;
            }
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值