25. Events (e起来编程”(武汉网络赛)) 线段树(区间修改,区间查询)

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<n105)

The second line contains nn integers, the ii-th one of them is t_iti, which is the planning time of contest ii at the beginning of this year. (0\le t_i \le 10^90ti109)

The third line contains an integer qq. And then qq lines follows. (0 < q \le 10^50<q105)

Then each line contains three integers. L_iLiR_iRiT_iTi, means the time of L_iLi-th contest to R_iRi-th contest will be changed by T_iTi. And then you should output the earlist time of L_iLi-th contest to R_iRi-th contest in the history after the change of time. (0 < L_i \le R_i \le n0<LiRin|T_i| \le 10^9Ti109)

Output

Output contains qq lines, ii-th line is the answer after ii-th query.

Examples

Input 1

4
1 2 3 4
3
1 2 2
2 3 3
3 4 -10

Output 1

1
2
-6

Note

At the beginning, t_iti are (1,2,3,4)(1,2,3,4). After the first change on time, t_iti becomes (3,4,3,4)(3,4,3,4), and then (3,7,6,4)(3,7,6,4), and at last becomes (3,7,-4,-6)(3,7,4,6).

Be careful that as the times are relative times, so they can be negative.


题意:n场比赛,m次操作,每场比赛有个初值,操作每次把一个区间的比赛时间修改,每次修改完需要统计这个区间历史的时间最小值。


分析:线段树问题,区间修改和区间询问。

坑点:区间问题需要一个延迟标记 cur,如果多次对一个区间进行覆盖,延迟标记cur多次累加,而下面的节点没有随之进行更新就会出现无法更新到最小值。

比如这个测试数据:

8

0 0 0 0 0 0 0 0

4

1 2 -1

1 4 -1

1 4 1

2 2 0

最后的一组 答案是-2


处理:首先是变量,每个节点需要 有一个当前最小值m、一个历史最小值 lm,一个延迟标记累加和(和指的是延迟标记累加的得到的结果) cur,一个用来保存当cur多次累加时出现的最小和 mcur,一个延迟标记累加前的m值用 变量 sm 储存。当 rt 节点 pushdown时,需要更新 rt 节点 左右孩子节点lc和rc。更新lc节点的mcur时 ,mcur就等于min(cur(lc)+mcur(rt),mcur(lc)),然后  lm(lc) =min(mcur(lc)+sm(lc),lm(lc)),接着更新lc节点的cur和m,cur(lc)+=cur(rt),m(lc)+=cur(rt);


代码;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define mem(p,k) memset(p,k,sizeof(p));
#define rep(a,b,c) for(int a=b;a<c;a++)
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x6fffffff
#define ll long long
using namespace std;
const ll maxx=99999999999999999;
struct SD{
    ll sm,m,lm,cur,mcur;

}tree[110001<<2];
//vector<ll> mcur[110000<<2];//第一次我用数组来保存每一个cur,然后向下更新时分析两个cur数组来更新lm,然后超内存了,后来想到这样是不需要的。 
ll minn;
int n;
ll kmin(ll a,ll b){//取最小值 
    if(a>b)return b;
    return a;
}
void pushup(int rt){//每次pushup的时候把m的初值存在sm里。 
    tree[rt].sm=tree[rt].m=kmin(tree[rt<<1|1].m,tree[rt<<1].m);
    tree[rt].lm=kmin(tree[rt].lm,tree[rt].m);
}
void build(int l,int r,int rt){
    
    if(l==r){
        scanf("%lld",&tree[rt].m);
        tree[rt].sm=tree[rt].lm=tree[rt].m;
        tree[rt].cur=0;
        tree[rt].mcur=0;
        return;
    }
    tree[rt].cur=0;
    tree[rt].mcur=0;
    tree[rt].lm=maxx;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

void pushdown(int rt){// 更新mcur你可以想像成 B数组拼接在A数组后面,这时新的mcur就等于求新数组的以第一个数为起点的连续序列最小和。 
    
    if(tree[rt].cur||tree[rt].mcur){
        ll k=tree[rt].mcur;
        
        tree[rt<<1].mcur=kmin(tree[rt<<1].mcur,tree[rt<<1].cur+k);//tree【rt】.cur就是B数组的和,tree【rt<<1】.cur就是A数组的和, 
	                                                             //更新A数组的mcur需要比较 (B数组的mcur+A数组的cur)。 
        tree[rt<<1].cur+=tree[rt].cur;
        tree[rt<<1].lm=kmin(tree[rt<<1].mcur+tree[rt<<1].sm,tree[rt<<1].lm);//
        tree[rt<<1].m+=tree[rt].cur;
        
        tree[rt<<1|1].mcur=kmin(tree[rt<<1|1].mcur,tree[rt<<1|1].cur+k);
        tree[rt<<1|1].cur+=tree[rt].cur;
        tree[rt<<1|1].lm=kmin(tree[rt<<1|1].mcur+tree[rt<<1|1].sm,tree[rt<<1|1].lm);
        tree[rt<<1|1].m+=tree[rt].cur;

        tree[rt].cur=0;
        tree[rt].mcur=0;

    }
}
void update(int L,int R,ll c,int l,int r,int rt){

    if(L<=l&&r<=R){

        tree[rt].cur+=c;
        tree[rt].mcur=kmin(tree[rt].mcur,tree[rt].cur);
        tree[rt].m+=c;
        tree[rt].lm=kmin(tree[rt].mcur+tree[rt].sm,tree[rt].lm);

        
        return ;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m)update(L,R,c,lson);
    if(m<R)update(L,R,c,rson);
    pushup(rt);
    
}

void query(int L,int R,int l,int r,int rt){

    if(L<=l&&r<=R){
        
        minn=kmin(minn,tree[rt].lm);
        return ;
    }
    int m=(l+r)>>1;
    pushdown(rt);
    if(L<=m)  query(L,R,lson);
    if(m<R) query(L,R,rson);
    pushup(rt);
    
    return ;
}
int main()
{
    while(scanf("%d",&n)!=EOF){
       build(1,n,1);
       int q;
       cin>>q;
       while(q--){
           int x,y;
           ll l;
           scanf("%d%d%lld",&x,&y,&l);
           minn=maxx;
           update(x,y,l,1,n,1);
           query(x,y,1,n,1);
          //for(int i=1;i<=9;i++)
          //cout<<i<<"=="<<tree[i].cur<<" "<<tree[i].mcur<<" "<<tree[i].m<<"  "<<tree[i].lm<<endl;
           cout<<minn<<endl;
       }
    }

    return 0;
}
/*
50
215733813 307386685 520261529 450138662 949456829 671225339 934482534 186212823 355799555 356887611 
602672843 508909336 210692892 952637814 893261943 469925811 223390088 962250251 597375877 835756337 
723643811 562932720 149692260 757876154 704575774 220671023 684366264 738316954 73848422 861265352 
458520896 725076433 697684561 979865317 531515637 450141867 282487688 61794196 565099202 795853790 
549426545 25149102 703216304 4227519 575161865 376709205 110647653 205336767 369942388 980972085
50
2 28 -963136354
10 37 -493672652
12 18 353410130
6 10 -238033745
20 39 210523743
9 30 639347371
32 36 -9195713
17 30 -717008487
20 41 -36136651
13 30 734827945
18 39 385985574
17 20 -781779617
39 49 -45890750
22 29 -797081707
9 29 269748967
10 10 -558956770
34 47 -259870589
5 16 -412975964
35 42 877838251
37 43 735643842
7 10 214915316
29 34 107738902
21 45 -316467671
9 37 357210857
6 18 -593905100
41 45 -382417909
15 28 -497928944
6 22 359452747
11 48 687097677
28 42 -563855727
3 14 -68996650
36 43 -71816826
10 12 538338088
17 24 -987140243
44 50 -936308752
16 28 -162481260
14 24 -217404139
18 23 170083297
2 26 -508827885
26 32 -472701280
11 13 -314907746
23 48 -341890135
12 43 -23711835
3 38 -893028509
14 43 654578047
5 23 514877061
9 14 827768061
33 38 -452858266
4 21 -171971508
46 49 387029760

*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值