线段树专题

线段树专题

清单
· hdu1166 敌兵布阵
· hdu1754 I Heat It
· hdu1698 Just a Hook
· poj3468 A Simple Problem with Integers
· codeforces156A]
· 总结

写在前面

本文作为个人练习使用,不能保证思路每个人都看懂。但是可以提供由易到难的题目清单。

习题

1. hdu1166 敌兵布阵

//区间查询,点修改 (不含懒标记)

#include<iostream>
#include<cstdio>
#include<cstring>
#define lson tree[rt].l,mid,rt<<1
#define rson mid+1,tree[rt].r,rt<<1|1
using namespace std;
typedef long long ll;
const int maxn = 5e4+10;
int ans;
int a[maxn];
struct{
    int l,r,sum;
}tree[maxn<<2];

void build(int L,int R,int rt){
    tree[rt].l = L,tree[rt].r = R;
    if(tree[rt].l == tree[rt].r){
     //   tree[rt].sum = a[L];
        scanf("%d",&tree[rt].sum);
        return ;
    }
    int mid = (L + R)>>1;
    build(lson);
    build(rson);
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void add(int pos,int val,int rt){
    if(tree[rt].l == tree[rt].r){
        tree[rt].sum += val;
        return ;
    }
    int l = tree[rt].l, r = tree[rt].r;
    int mid = (l+r)>>1;
    tree[rt].sum += val;
    if(pos<=mid) add(pos,val,rt<<1);
    if(pos>mid) add(pos,val,rt<<1|1);
}

void query(int L,int R,int rt){
    int l = tree[rt].l, r = tree[rt].r;
    int mid = (l + r)>>1;
    if(L <=l && r <= R){
        ans += tree[rt].sum;
//        cout<<l<<" l r "<<r<<" tree[rt].sum "<<tree[rt].sum<<endl;
        return ;
    }
    if(L <= mid) query(L,R,rt<<1);
    if(R > mid) query(L,R,rt<<1|1);
}

int main(){
    int t; scanf("%d",&t);
    for(int p=1;p<=t;p++){
        printf("Case %d:\n",p);
        int n; scanf("%d",&n);
 //       for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,n,1);
        char op[10];int L,R,pos,val;
        while(1){
            scanf("%s",op);
            if(op[0] == 'E')
                break;
            if(op[0] == 'A'){
                scanf("%d%d",&pos,&val);
                add(pos,val,1);
            }
            if(op[0] == 'S'){
                scanf("%d%d",&pos,&val);
                add(pos,-val,1);
            }
            if(op[0] == 'Q'){
                ans = 0;
                scanf("%d%d",&L,&R);
                query(L,R,1);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
/*
1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End

Case 1:
6
33
59
*/

2. hdu1754 I Heat It

//单点更新 查询区间最值 (不含懒标记)

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
struct{
    int l, r,maxx;
}tree[maxn<<2];
int a[maxn];
void build(int l,int r,int rt){
    tree[rt].l = l; tree[rt].r = r;
    if(l == r){
        tree[rt].maxx = a[l];
        return ;
    }
    int mid = (l + r)>>1;
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    tree[rt].maxx = max(tree[rt<<1].maxx,tree[rt<<1|1].maxx);
}

int query(int l,int r,int rt){
    if(tree[rt].l >= l && tree[rt].r <= r)
        return tree[rt].maxx;
    int mid = (tree[rt].l + tree[rt].r)>>1;                         //误写成mid = (l+r)>>1
    if(r <= mid){
        return query(l,r,rt<<1);
    }
     if(l > mid){
        return query(l,r,rt<<1|1);
    }
    if(r > mid&&l<=mid){
        return max(query(l,mid,rt<<1),query(mid+1,r,rt<<1|1));
    }
}

//int query(int l,int r,int rt){
//    if(l <= tree[rt].l && tree[rt].r <= r){
//        return tree[rt].maxx;
//    }
//    int mid = (tree[rt].l + tree[rt].r)>>1;
//    int MAX = -1;
//    if(l <= mid)                            //fuck(r<=mid)
//        MAX  = max(MAX,query(l,r,rt<<1));
//    if(r > mid)
//        MAX = max(MAX,query(l,r,rt<<1|1));
//    return MAX;
//}

void update(int pos,int k,int rt){
    if(tree[rt].l == tree[rt].r){
        tree[rt].maxx = k;
        return ;
    }
    int mid = (tree[rt].l + tree[rt].r)>>1;
    if(pos <= mid){
        update(pos,k,rt<<1);                           //误写成update(tree[rt].l,mid,rt<<1);
    }
    else{
        update(pos,k,rt<<1|1);
    }
    tree[rt].maxx = max(tree[rt<<1].maxx,tree[rt<<1|1].maxx);
}

int n,m;
int main(){
        while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,n,1);

        while(m--){
            char op[5];int l,r;
            scanf("%s%d%d",op,&l,&r);
            if(op[0] == 'U'){
                update(l,r,1);
            }
            if(op[0] == 'Q'){
                printf("%d\n",query(l,r,1));
            }

//            for(int i= 1 ;i<=4*n;i++){
//                cout<<tree[i].maxx<<' ';
//            }
//            cout<<endl;

        }
    }
    return 0;
}
/*
5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5

5
6
5
9
*/

3. hdu1698 Just a Hook

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;

struct{
    int l,r,val,lazy;
}tree[maxn<<2];

int getlen(int rt){
    return tree[rt].r - tree[rt].l + 1;
}

void push_down(int rt){
    if(tree[rt].lazy){
        tree[rt<<1].lazy = tree[rt].lazy;
        tree[rt<<1|1].lazy = tree[rt].lazy;
        tree[rt<<1].val = getlen(rt<<1)*tree[rt].lazy;
        tree[rt<<1|1].val = getlen(rt<<1|1)*tree[rt].lazy;
        tree[rt].lazy = 0;
    }
}

void build(int l,int r,int rt){
    tree[rt].l = l, tree[rt].r = r,tree[rt].lazy = 0;
    int mid = (l + r)>>1;
    if(l == r){
        tree[rt].val = 1;
        return ;
    }
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    tree[rt].val = tree[rt<<1].val + tree[rt<<1|1].val;
}

void update(int L,int R,int num,int rt){
    int l = tree[rt].l, r = tree[rt].r;
    if(L <= l && r <= R){
        tree[rt].lazy = num;
        tree[rt].val = getlen(rt)*num;
        return ;
    }
    push_down(rt);
    int mid = (l + r)>>1;
    if(L<=mid) update(L,R,num,rt<<1);
    if(R>mid) update(L,R,num,rt<<1|1);
    tree[rt].val = tree[rt<<1].val + tree[rt<<1|1].val;
}

int query(){
    return tree[1].val;
}

int main(){
    int ma=maxn<<2+1;
    cout<<ma<<endl;
    int t;int cnt = 0;
    scanf("%d",&t);
    while(t--){
        cnt++;
        int n,m; scanf("%d%d",&n,&m);
//        for(int i=1;i<=(n<<2+2);i++) tree[i].lazy = 0;
        build(1,n,1);
        int L,R,val;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&L,&R,&val);
            update(L,R,val,1);
        }
        printf("Case %d: The total value of the hook is %d.\n",cnt,query());
    }
    return 0;
}
/*
4
10
2
1 5 2
5 9 3
10
2
2 5 2
5 9 2
10
2
1 3 3
5 5 3
10
2
1 8 3
5 8 2

Case 1: The total value of the hook is 24.
*/

4. poj3468 A Simple Problem with Integers

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
struct{
    ll l,r;
    ll lazy;
    ll sum;
}tree[(maxn<<2)+10];

ll getlen(int rt){
    return tree[rt].r - tree[rt].l + 1;
}
ll ans;
void push_down(int rt){
    if(tree[rt].lazy){
        tree[rt<<1].lazy += tree[rt].lazy;
        tree[rt<<1|1].lazy += tree[rt].lazy;
        tree[rt<<1].sum += tree[rt].lazy*getlen(rt<<1);
        tree[rt<<1|1].sum += tree[rt].lazy*getlen(rt<<1|1);
        tree[rt].lazy = 0;
    }
}

void build(ll l,ll r,int rt){
    tree[rt].l = l, tree[rt].r = r,tree[rt].lazy=0;
    ll mid = (l + r)>>1;
    tree[rt].sum=0;
    if(l == r){
        scanf("%lld",&tree[rt].sum);
        return ;
    }
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void update(ll L,ll R,ll charge,int rt){
    ll l = tree[rt].l, r = tree[rt].r;
    ll mid = (l + r)>>1;
    if(L <= l && r <= R){
        tree[rt].lazy += charge;
        tree[rt].sum += getlen(rt)*charge;
        return ;
    }
    push_down(rt);
    if(L <= mid) update(L,R,charge,rt<<1);
    if(mid < R) update(L,R,charge,rt<<1|1);
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void query(ll L,ll R,int rt){
    ll l = tree[rt].l, r = tree[rt].r;
    ll mid = (l + r)>>1;
    if(L <= l && r <= R){
        ans += tree[rt].sum;
        return ;
    }
    push_down(rt);
    if(L <= mid) query(L,R,rt<<1);
    if(mid < R) query(L,R,rt<<1|1);
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

int main(){
    ll n,m;
    while(~scanf("%lld%lld",&n,&m)){
        build(1,n,1);
//        for(ll i=1;i<=(n<<2)+2;i++) tree[i].lazy = 0;
        char op[10];
        while(m--){
            scanf("%s",op);ll L,R,charge;
            if(op[0] == 'Q'){
                scanf("%lld%lld",&L,&R);
                ans = 0;
                query(L,R,1);
                printf("%lld\n",ans);
            } else{
                scanf("%lld%lld%lld",&L,&R,&charge);
                update(L,R,charge,1);
            }
        }
    }
    return 0;
}
/*
10 11
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
C 2 4 4
Q 1 3
C 5 9 6
Q 4 7
C 1 1 2
Q 1 1

4
55
9
15
17
53
3
*/

5. codeforces356A

  1. 可以用并查集
  2. 可以用set
  3. 可以用线段树
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn = 3e5+10;
int a[maxn];
struct{
    int l, r, endd;
}tree[maxn<<2];

void build(int l,int r,int rt){
    tree[rt].l = l, tree[rt].r = r;
    if(l == r) return ;
    int mid = (l + r)>>1;
    build(l , mid , rt<<1);
    build(mid + 1, r , rt<<1|1);
}

void update(int L,int R,int num,int rt){
    int l = tree[rt].l, r = tree[rt].r;
    int mid = (l + r)>>1;
    if(tree[rt].endd){
            if(a[tree[rt].endd] == 0 && num != tree[rt].endd) a[tree[rt].endd] = num;
        return ;
    }
    if(L <= l && r <= R){
        tree[rt].endd = num;
        for(int i=l;i<=r;i++){
            if(i != num && a[i] == 0) a[i] = num;
        }
        return ;
    }
    if(L <= mid) update(L,R,num,rt<<1);
    if(mid < R) update(L,R,num,rt<<1|1);
}

int main(){
    int n,m; scanf("%d%d",&n,&m);
    build(1,n,1);
    int L,R,val;
    while(m--){
        scanf("%d%d%d",&L,&R,&val);
        update(L,R,val,1);
    }
    for(int i=1;i<=n;i++){
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

6. 最大连续子段和

题意

点修改,求区间最大连续子段和。

注意

  1. 这里的query的push_up非常巧妙。返回结构体,而且不是正常的子树向父节点的push_up。
  2. 我们的TREE里有几个参数是,一点一点发现需要用到的,比如我们发现要求lmax和rmax,接着发现还需要求sum。
/*
 * Author:  Chen_zhuozhuo
 * Created Time:  2020/3/18 11:35:20
 * File Name: a.cpp
 */
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <time.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxint = -1u>>1;
const int inf = 0x3f3f3f3f;
const int maxn = 5e5 + 10;
int n,m,a[maxn],op,L,R,pos,val;

int Max(int a, int b, int c){
    return max(a, max(b, c));
}

struct TREE{
    int l, r, sum, lmax, rmax, max;
}tree[maxn<<2];

void push_up(int rt){
    tree[rt].max= Max(tree[rt<<1].max, tree[rt<<1|1].max, tree[rt<<1].rmax + tree[rt<<1|1].lmax);
    tree[rt].lmax = max(tree[rt<<1].lmax, tree[rt<<1].sum + tree[rt<<1|1].lmax), tree[rt].rmax = max(tree[rt<<1|1].rmax, tree[rt<<1|1].sum + tree[rt<<1].rmax);
    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}

void build(int L, int R, int rt){
    tree[rt].l = L, tree[rt].r = R;
    if(L == R){
        tree[rt].sum = tree[rt].lmax = tree[rt].rmax = tree[rt].max = a[L];
        return ;
    }
    int mid = L + R >> 1;
    build(L, mid, rt<<1);
    build(mid + 1, R, rt<<1|1);
    push_up(rt);
}

void update(int pos, int val, int rt){
    int l = tree[rt].l, r = tree[rt].r;
    if(l == r){
        tree[rt].max = tree[rt].sum = tree[rt].lmax = tree[rt].rmax = val;
        return ;
    }
    int mid = l + r >> 1;
    if(pos <= mid){
        update(pos, val, rt<<1);
    }
    if(pos > mid){
        update(pos, val, rt<<1|1);
    }
    push_up(rt);
}

TREE query(int L, int R, int rt){
    int l = tree[rt].l, r = tree[rt].r;
    if(L <= l && r <= R)
        return tree[rt];
    int mid = l + r >> 1;
    if(R <= mid)
        return query(L, R, rt<<1);
    else if(L > mid)
        return query(L, R, rt<<1|1);
    else{
        TREE res, left, right;
        left = query(L, R, rt<<1);
        right = query(L, R, rt<<1|1);
        res.sum = left.sum + right.sum;
        res.max = Max(left.max, right.max, left.rmax + right.lmax);
        res.lmax = max(left.lmax, left.sum + right.lmax);
        res.rmax = max(right.rmax, right.sum + left.rmax);
        return res;
    }
}

int main() {
    cin>>n>>m;
    for(int i=1; i<=n; i++){
        cin>>a[i];
    }
    build(1, n, 1);
    for(int i=1; i<=m; i++){
        cin>>op;
        if(op == 1){
            cin>>L>>R;
            if(L > R)
                swap(L, R);
            cout<<query(L, R, 1).max<<endl;
        }
        else{
            cin>>pos>>val;
            update(pos, val, 1);
        }
    }
    return 0;
}

/*
输入样例:
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
输出样例:
2
-1 
*/

总结

  1. push_down在 if (L <= l && r <= R)之后,否则在叶子节点接着向下访问,会导致数组越界RE
  2. 在update中,先下传懒标记在push_up.
  3. 懒标记是给儿子用的. 儿子用父亲的lazy_tag。
    例.tree[rt<<1].sum += tree[rt].lazy * getlen(rt<<1);
  4. push_up操作一共有3次
    (1)Query() 对于大多数运算,应该是可以不加push_up的.因为原本tree[rt].sum=getlen(rt) * lazy;加上push_up后tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum即tree[rt].lazygetlen(rt<<1)+tree[rt].lazygetlen(rt<<1|1);
    提取公因式后,得到tree[rt].lazy*(getlen(rt<<1)+getlen(rt<<1|1)),即tree[rt].lazy*getlen(rt);两者应当是相等的。
    但是如果本题不是加法,而是不满足结合律的运算。最好加上push_up。
    (2)Update()
    (3)Build()
  5. push_down操作一共有两次
    (1)Update()
    (2)Query()
  6. tree[maxn<<2+100] 加运算优先,变成了左移102位,int(32位)左移102是0.(居然报tle)
  7. 最容易出错的地方
    (1)+= 写成 =
    (2)如图所示
    常见错误

(3)如图所示1111

  1. push_donw什么时候用?破坏区间一致性的时候。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值