武大网络赛D题

D. Events

D.Events
题意是给一个数组,有q次操作,每次对一个区间加上一个数字,然后求这个区间的历史最小值。
这道题真的想了很久,用很多种方法去尝试,其实想明白了真的很简单。
我们建一棵线段树,记录两个东西,一个是区间最小值,一个是区间历史最小值。但是有个非常非常关键点地方,就是当Pushdown的时候,不能直接像普通区间更新一样,如果当前的lazy是负数,而且即将更新下来的lazy是正数,应该先把负数往下去更新。因为这里面存在着一个先后顺序,如果先减了则历史最小值变小了。

#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<iostream>
using namespace std;
#define  LONG long long
const int   INF=0x3f3f3f3f;
const int MOD=1e9+7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define root 1 , n , 1
#define lson  l , mid , rt<< 1
#define rson  mid + 1 ,r , (rt<<1)+1
const int MAXN = 1e5+10;
int n ;
struct Tree
{
    LONG Min , HisMin ;
}tree[MAXN<<3];
LONG lazy[MAXN<<3] ;
void Push_up(  int rt)
{
    tree[rt].Min = min( tree[rt<<1|1].Min , tree[rt<<1].Min) ;
    tree[rt].HisMin = min(min(min (tree[rt].HisMin , tree[rt].Min) , tree[rt<<1].HisMin ) , tree[rt<<1|1].HisMin );
}
void build_tree(int l , int r , int rt)
{
    lazy[rt] = 0;
    if(l == r)
    {
        scanf("%lld",&tree[rt].Min ) ;
        tree[rt].HisMin = min ( tree[rt].HisMin , tree[rt].Min) ;
        return ;
    }
    int mid = ( l + r ) / 2;
    build_tree(l , mid , rt <<1) ;
    build_tree( mid + 1 , r , rt << 1 | 1) ;
    Push_up(rt) ;
}
void Pushdown(int rt)
{
    if(rt > n * 4 + 100) return ;
    if(1)
    {
        //
        if(lazy[rt<<1] < 0 && lazy[rt] >= 0) Pushdown(rt<<1) ;
        lazy[rt<<1] += lazy[rt ] ;
        if(lazy[rt<<1|1] < 0 && lazy[rt] >= 0) Pushdown(rt<<1|1) ;
        lazy[rt << 1| 1] += lazy[rt] ;
        //
        tree[rt<<1].Min += lazy[rt] ;
        tree[rt<<1|1].Min += lazy[rt] ;
        lazy[rt] = 0;
        tree[rt].HisMin = min(min(min (tree[rt].HisMin , tree[rt].Min) , tree[rt<<1].HisMin ) , tree[rt<<1|1].HisMin );
    }
}
void Update(int L , int R , int l , int r , int rt , int val )
{
    tree[rt].HisMin = min(min(min (tree[rt].HisMin , tree[rt].Min) , tree[rt<<1].HisMin ) , tree[rt<<1|1].HisMin );
    if( L <= l && r <= R)
    {
        lazy[rt] += val ;
        tree[rt].Min += (LONG ) val ;
        tree[rt].HisMin = min(min(min (tree[rt].HisMin , tree[rt].Min) , tree[rt<<1].HisMin ) , tree[rt<<1|1].HisMin );
        return ;
    }
    int mid = ( l + r) / 2;
    Pushdown( rt) ;
    if( L <= mid)
        Update(L ,R ,lson , val ) ;
    if( R > mid )
        Update(L ,R , rson,val ) ;
    Push_up(rt) ;
}
LONG  Query(int L ,int R , int l , int r , int rt)
{
    tree[rt].HisMin = min(min(min (tree[rt].HisMin , tree[rt].Min) , tree[rt<<1].HisMin ) , tree[rt<<1|1].HisMin );
    if( L <= l && r <= R)
    {
        if(lazy[rt] < 0 ) Pushdown(rt) ;
        return tree[rt].HisMin ;
    }
    int mid = (l + r) /2;
    Pushdown(rt) ;
    LONG  res = INF ;
    if(L <= mid )
        res =  min( res , Query(L , R , lson)) ;
    if( R > mid)
        res = min (res , Query( L , R ,rson)) ;
    return res ;
}
int main()
{
    while(cin >> n)
    {
       clr1(tree);
       clr0(lazy);
        build_tree(root ) ;
        int q ;
        cin>> q;
        int l ,r ;
        int x;
        for(int i = 1;  i <= q ; ++i)
        {
            scanf("%d%d%d",&l,&r,&x);
            Update(l ,r , root , x) ;
            printf("%lld\n",Query(l ,r , root)) ;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值