区间更新POJ3468 HDU1698

来源:互联网 发布:2017网络吉他大赛 编辑:程序博客网 时间:2024/05/08 18:30

网址https://vjudge.net/problem/POJ-3468
最近学了线段树,搞了一下区间更新。模板题吧。
写一下自己需要记住的点吧。
1.空间要为节点数的4倍,我在网上找了一下,大概意思是这样
建树后可能出现这种情况这里写图片描述(图片来自http://scinart.github.io/acm/2014/03/19/acm-segment-tree-space-analysis/)
结果在最下面的一行原本没完全使用却占用了空间,占用的是比这个图刚刚大的完美二叉树空间。
计算一下此图空间:((n-1)*2-1+1)*2-1=4n-5
n-1倒数第二行空间。*2-1,,除去最后一行的总空间,,+1最后一行空间。
2.类型要为long long int 类型,因为最后会超int范围
3.被标记的点已经更新完信息。等待向下更新标记。
4.延迟标记。
思想:对于要更新的区段,将其记录在祖先节点,而不完全将祖先节点记录整个区间
的子孙节点信息更新。当需要使用其下的子孙节点时再向下更新信息。这种方式大大减少了
时间复杂度。
方式:修改与查询时,遇到节点,查看其是否被标记。是的话就向下传递标记,更新子节点信息,并消除父节点标记。
5.建立的图如下。。。(好丑)
这里写图片描述
6.具体地方在里面备注

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;/******************************************************/#define LL long long int#define mem(a,b) memset(a,b,sizeof(a))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define L rt<<1#define R rt<<1|1#define N 100000+9#define pow(a) a*a#define INF 0x3f3f3f3f#define max(a,b) (a>b?a:b)#define min(a,b) (a<b?a:b)/*********************************************************/LL n, q;LL dat[N<<2];LL sum[N<<2];LL addmark[N<<2];void pushup(LL rt){    sum[rt] = sum[L] + sum[R];}void pushdown(LL rt, LL len){    if (addmark[rt])    {        addmark[L] += addmark[rt];        addmark[R] += addmark[rt];        sum[L] += addmark[rt]*(len - (len>>1));//这里要用rt,不用L。加更改后的值        sum[R] += addmark[rt]*(len>>1);        addmark[rt] = 0;    }}void build(LL l, LL r, LL rt){    addmark[rt] = 0;    if (l == r){        scanf("%lld", &sum[rt]);        return;    }    LL m = (l + r) / 2;    build(lson);    build(rson);    pushup(rt);}LL query(LL a,LL b,LL l, LL r, LL rt){    if (a <= l&&r <= b){        return sum[rt];    }    LL m = (l + r) / 2;    LL res = 0;    pushdown(rt, r - l + 1);    if (a <= m)res+=query(a, b, lson);    if (b>m)res+=query(a, b, rson);    return res;}void update(LL a, LL b, LL l, LL r, LL rt, LL c){    if (a <= l&&r <= b){        addmark[rt] += c;           sum[rt] += c * (r - l + 1);        return;    }    pushdown(rt, r-l+1);    //向下传递标记,更新左右儿子信息    LL m = (l + r) / 2;    if(a<=m)update(a, b, lson, c);    if(b>m)update(a, b, rson, c);    pushup(rt);    //向上更新}int main(){    while (~scanf("%lld%lld", &n, &q))    {        build(1, n, 1);        while (q--){            char s[2];            scanf("%s", s);            if (s[0] == 'Q'){                LL a, b;                scanf("%lld%lld", &a, &b);                LL res = query(a, b, 1, n, 1);                printf("%lld\n", res);            }            else{                LL a, b, c;                scanf("%lld%lld%lld", &a, &b, &c);                update(a, b, 1, n, 1, c);            }        }    }}

HDU1689区间更新

更新的时候,从顶节点一路往下推。当遇到标记时,将标记向下传递。因为在某区间段更新是在递归最后实现的,所以之前的传递造成的标记会被更新的标记覆盖。更新结束之后,要实现求和的功能。

求和过程也是一路从上往下找。当遇到有标记的节点时,就返回标记的值*区间长度,即该区间的总和。当搜寻到叶子节点,即l==r时,如果有标记,返回标记,没有则返回1(初始值为1,不曾改变)

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>using namespace std;/******************************************************/#define LL long long int#define mem(a,b) memset(a,b,sizeof(a))#define m ((l+r)/2)#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define L rt<<1#define R rt<<1|1#define N 100000+1#define pow(a) a*a#define INF 0x3f3f3f3f#define max(a,b) (a>b?a:b)#define min(a,b) (a<b?a:b)/*********************************************************//*11021 5 25 9 3*/LL t, n, q;LL addmark[N<<2];void pushdown(LL rt){    if (addmark[rt])    {            addmark[L] = addmark[rt];            addmark[R] = addmark[rt];        addmark[rt] = 0;    }}void update(LL a, LL b, LL c, LL l, LL r, LL rt){    if (a<=l&&r<=b){        addmark[rt] = c;        return;    }    pushdown(rt);    if (a <= m)update(a, b, c, lson);    if (b > m)update(a, b, c, rson);}LL add(LL l, LL r, LL rt){    if (addmark[rt]){        return addmark[rt] * (r - l + 1);    }    if (l == r){        if (addmark[rt])            return addmark[rt];        else            return 1;    }    LL res = 0;    res+=add(lson);    res+=add(rson);    return res;}int main(){    cin >> t;    LL cnt = 1;    while (t--){        mem(addmark, 0);        scanf("%lld%lld", &n, &q);        while (q--){            LL a, b, c;            scanf("%lld%lld%lld", &a, &b, &c);            update(a, b, c, 1, n, 1);        }        printf("Case %lld: The total value of the hook is %lld.\n",cnt++, add(1, n, 1));    }}
0 0
原创粉丝点击