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)) ;
}
}
}