2017武汉大学校赛网络预选赛d题

本文介绍了一种使用段式树解决区间更新和查询问题的方法。通过递归地将整个区间划分为多个子区间,可以高效地进行区间更新操作及查询历史最小值。此方法适用于动态调整大量数据并频繁查询特定区间最小值的场景。

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

Input file: standard input
Output file: standard output
Time limit: 1 second
Memory limit: 512 mebibytes
Every year, the ACM/ICPC team will hold many contests, some of them are training while others are school contests.

In the year of 2017, there are nn contests to be held, and at the beginning of year, we plans the time of each contest.

However, as things are changing. Some other events might affect the time of contest and our team leader wants to know some interesting things about the time of some events.

Input
The first line contains an integer nn. (0 < n \le 10^50

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll inf = 1e18;
ll ans;
int n,q;
struct node{
    int l, r;
    ll nowMin;//当前区间最小值
    ll hisMin;//历史区间最小值
    ll add;//延迟标记
}Node[maxn*4];
void pushUp(int i)
{
    if(Node[i].l == Node[i].r) return;
    int s1 = i<<1;
    int s2 = s1 + 1;
    Node[i].nowMin = min(Node[s1].nowMin,Node[s2].nowMin);
    Node[i].hisMin = min(Node[i].hisMin,Node[i].nowMin);
}
void pushDown(int i)
{
    int s1 = i<<1;
    int s2 = s1 + 1;
    Node[s1].add += Node[i].add;
    Node[s2].add += Node[i].add;
    Node[i].add = 0;
}
void build(int i,int l,int r)
{
    Node[i].l = l;
    Node[i].r = r;
    Node[i].add = 0;
    Node[i].hisMin = inf;
    if(l == r)
    {
        scanf("%lld",&Node[i].nowMin);
        Node[i].hisMin = Node[i].nowMin;
        return;
    }
    int f = i;
    int mid = (l + r)>>1;
    i <<= 1;
    build(i,l,mid);
    build(i + 1,mid + 1,r);
    pushUp(f);
}
void up_down(int i,int l,int r,ll value)
{
    Node[i].nowMin += value;
    Node[i].hisMin = min(Node[i].hisMin,Node[i].nowMin);
    if(l == r) return;
    if(value > 0&&Node[i].add < 0)
    {
        /****************
        这一题的巧妙之处就在于这点,当这个区间每个数都要加上一个value时,
        如果此时value > 0,并且标记小于0时,要把标记先向下更新,为什么要这样做。
        我门们设想一下,此时标记是负数,当它更新下去时,一定可以使下面的每个区间的当前最小值变小,
        有可能使历史最小值变小,但是如果不这样更新的话,直接加上value,就会导致这个负数变大,从而使
        下面本该变小的没有变小,自己想一下为什么,我这题交了50多遍,心累。
        ****************/
        int s1 = i<<1;
        int s2 = s1 + 1;
        up_down(s1,Node[s1].l,Node[s1].r,Node[i].add);
        up_down(s2,Node[s2].l,Node[s2].r,Node[i].add);
        Node[i].add = value;
    }
    else
    {
        Node[i].add += value;
    }
}
void update(int i,int l,int r,ll value)
{
    if(l == Node[i].l&&r == Node[i].r)
    {
        up_down(i,l,r,value);
        return;
    }
    if(Node[i].add)
    {
        int s1 = i<<1;
        int s2 = s1 + 1;
        up_down(s1,Node[s1].l,Node[s1].r,Node[i].add);
        up_down(s2,Node[s2].l,Node[s2].r,Node[i].add);
        Node[i].add = 0;
    }
    int f = i;
    i <<= 1;
    if(r <= Node[i].r) update(i,l,r,value);
    else if(l >= Node[i + 1].l) update(i + 1,l,r,value);
    else
    {
        update(i,l,Node[i].r,value);
        update(i + 1,Node[i + 1].l,r,value);
    }
    pushUp(f);
    return;
}
void query(int i,int l,int r)
{
    if(l == Node[i].l&&r == Node[i].r)
    {
        ans = min(ans,Node[i].hisMin);
        return;
    }
    if(Node[i].add)
    {
        int s1 = i<<1;
        int s2 = s1 + 1;
        up_down(s1,Node[s1].l,Node[s1].r,Node[i].add);
        up_down(s2,Node[s2].l,Node[s2].r,Node[i].add);
        Node[i].add = 0;
    }
    i <<= 1;
    if(r <= Node[i].r) query(i,l,r);
    else if(l >= Node[i + 1].l) query(i + 1,l,r);
    else
    {
        query(i,l,Node[i].r);
        query(i + 1,Node[i + 1].l,r);
    }
    return;
}
int main()
{
    scanf("%d",&n);
    build(1,1,n);
    scanf("%d",&q);
    int l,r;
    ll t;
    for(int i = 1; i <= q; i++)
    {
        scanf("%d%d%lld",&l,&r,&t);
        update(1,l,r,t);
        ans = inf;
        query(1,l,r);
        printf("%lld\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值