A.Ocean的礼物线段树

本篇介绍了一个关于区间更新与查询的问题,通过构造线段树实现对路段上特定区间内的礼物数量进行高效计算。当路段上的数字发生变化时,能够快速调整并准确给出任意指定区间内可获取礼物的数量。

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

A: Ocean的礼物 
Time Limit: 2 s Memory Limit: 128 MB 
Submit My Status 
Problem Description 
皇家理工存在一段很神奇的路段,这段路由nn个格子组成,每个格子都有一个数字,你可以走这段路的任意一段。这段路的神奇之处就在于,如果你所处的这个格子数字和你经过的前一个格子数字不相同的话,你就可以获得一个礼物(初始一定可以获得礼物)。现在Ocean想知道,给定任意路段的左边界和右边界,问若走这段路可以获得多少礼物。不过幸运的是,Ocean很快就解决了,并且获得了大量的礼物。玩的十分开心。但是有一天,这段路神奇的发生了改变。它不但会给你礼物。它还可能随时的改变其任意某处的格子上的数字。这下Ocean可就犯愁了,他想知道任意一段路可以获得的礼物是多少。聪明的你可以帮下他吗?

Input 
第一行输入一个整数nn,代表格子数。(1≤n≤106)(1≤n≤106) 
第二行输入nn个整数xx。(1≤x≤108)(1≤x≤108) 
第三行输入一个整数mm,代表mm次操作。(1≤m≤2∗105)(1≤m≤2∗105) 
接下来第四行到3+m3+m行每行33个数op,x,yop,x,y。

若op=1op=1则把xx处的数修改为yy。(1≤x≤n,1≤y≤108)(1≤x≤n,1≤y≤108) 
若op=2op=2,询问区间[x,y][x,y]内可以获得的礼物数。(1≤x≤y≤n)(1≤x≤y≤n) 
Output 
对于每个询问输出一个整数,代表可以获得的礼物数

Sample Input 

1 2 3 4 5 6 

2 1 6 
1 2 3 
2 2 3 
2 3 4 
Sample Output 


2

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int cnt,a[1111111];
struct node
{
    int l,r,val;
}p[2222222];
void pushup(int i)
{
    p[i].val=p[i<<1].val+p[i<<1|1].val;
}
void build(int i,int x,int y)
{
    p[i].l=x;
    p[i].r=y;
    if(p[i].r==p[i].l)
    {
        int pos=p[i].l;
        if(a[pos]!=a[pos-1]||pos==1)
            p[i].val=1;
        else p[i].val=0;
        return;
    }
    int m=p[i].r+p[i].l>>1;
    build(i<<1,x,m);
    build(i<<1|1,m+1,y);
    pushup(i);
}
void update(int i,int x,int val)
{
    if(p[i].l==p[i].r)
    {
        p[i].val=val;
        return;
    }
    int m=p[i].r+p[i].l>>1;
    if(x<=m)
        update(i<<1,x,val);
    if(x>m)
        update(i<<1|1,x,val);
    pushup(i);
}
void query(int i,int x,int y)
{
    if(p[i].l>=x&&p[i].r<=y)
    {
        cnt+=p[i].val;
        return;
    }
    int m=p[i].l+p[i].r>>1;
    if(x<=m)
        query(i<<1,x,y);
    if(y>m)
        query(i<<1|1,x,y);
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    int Q;
    scanf("%d",&Q);
    while(Q--)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==1)
        {
            a[y]=z;
            if(y>1)
            {
                if(a[y]==a[y-1])
                    update(1,y,0);
                else
                    update(1,y,1);
            }
            if(y<n)
            {
                if(a[y]==a[y+1])
                    update(1,y+1,0);
                else
                    update(1,y+1,1);
            }
        }
        if(x==2)
        {
            cnt=1;
            query(1,y+1,z);
            printf("%d\n",cnt);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值