浅谈具有各种特点的线段树

有关线段树的各种版本我也是从去年结束OI之后就再也没有碰过了,现在看到各种树觉得也是无从下手晕的很,拖拖拉拉一直三四天才弄出来一个专题。

重新扒出来看一眼各种树怎么写,然后写写博客记录一下心里历程(无言吐槽)

言归正传,先来说一下我对线段树这个美好东西的理解。

1.其实我觉得最简单的就是线段树的板子

2.如果你看一道题看一份题解看不懂然后人家告诉你这是线段树你说“怎么可能这是线段树?” 这种现象非常正常。

线段树专题一:单点更新

题目形如:求某个区间内的最大值,更新某个节点之后求和等。总之就是不涉猎区间更新的问题(其实也就是TLE的问题,不然不TLE谁去用lazytag)

I hate it(hdu 1754) 
题目描述: 
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。 
这让很多学生很反感。不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。 
本题目包含多组测试 
在每个测试的第一行,有两个正整数 N 和 M ( 0~N<=200000,0~M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。接下来有M行。每一行有一个字符 C (只取’Q’或’U’) ,和两个正整数A,B。 当C为’Q’的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。 当C为’U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。 对于每一次询问操作,在一行里面输出最高成绩。 输入 本题目包含多组测试,请处理到文件结束。 在每个测试的第一行,有两个正整数 N 和 M 分别代表学生的数目和操作的数目。 学生ID编号分别从1编到N。 第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。 接下来有M行。每一行有一个字符 C (只取’Q’或’U’) ,和两个正整数A,B。 当C为’Q’的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。 当C为’U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。 输出 对于每一次询问操作,在一行里面输出最高成绩。 样例输入
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 ---------------------
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXX = 200000;
struct node{
    int l,r,val;
}tree[MAXX*4+5];

int a[MAXX+5];
int max(int x,int y){
    if(x>y){
        return x;
    }else{
        return y;
    }
}
int build(int p,int l,int r){
    tree[p].l=l;
    tree[p].r=r;
    if(l == r){
        tree[p].val = a[l];
    }
    int mid = (l+r)/2;
    int x1 = build(p<<1,l,mid);
    int x2 = build(p<<1|1,mid+1,r);
    tree[p].val = max(x1,x2);
    return tree[p].val;
}
int update(int p,int x){
    if(x<tree[p].l || x>tree[p].r)
        return tree[p].val;
    if(tree[p].l==tree[p].r)
    {   
        tree[p].val=a[tree[p].l];
        return tree[p].val;
    }
    int x1=update(2*p,x);
    int x2=update(2*p+1,x);
    tree[p].val=max(x1,x2);
    return tree[p].val;

}
int query(int p,int x,int y)//查询
{
    if(y<tree[p].l || x>tree[p].r)
        return 0;
    if(x<=tree[p].l && tree[p].r<=y)
        return tree[p].val;
    int x1=query(2*p,x,y);
    int x2=query(2*p+1,x,y);
    return max(x1,x2);
}

int main(){
       int i,j,k,m,n;int x,y;char c;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)   scanf("%d",&a[i]);
    create_tree(1,1,n);
    for(i=1;i<=m;i++)
    {
        getchar();
        scanf("%c%d%d",&c,&x,&y);
        if(c=='Q')
            {printf("%d\n",query(1,x,y));}
        else
            {a[x]=y;update(1,x);}
    }
    return 0;

}

 

线段树专题二:区间更新

这里就用lazytag了,不用会TLE..比如luogu的T3372

#include<cstdio>
#include<iostream>
using namespace std;

const int MAXX = 100000;

struct node{
    int l,r;
    long long val,laz;
}tree[MAXX*4+2];

int a[MAXX+5];

void build(int p,int l,int r){
    tree[p].l = l;
    tree[p].r = r;
    if(l == r){
        tree[p].val = a[l];
        return;
    }
    int mid = (l+r)/2;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    tree[p].val = tree[p<<1].val + tree[p<<1|1].val;
}

void pushdown(int p){
    if(tree[p].laz != 0){
        tree[p<<1].val += tree[p].laz*(tree[p<<1].r-tree[p<<1].l+1);
        tree[p<<1|1].val += tree[p].laz*(tree[p<<1|1].r-tree[p<<1|1].l+1);
        tree[p<<1].laz += tree[p].laz;
        tree[p<<1|1].laz += tree[p].laz;
        tree[p].laz = 0;
    }
}

void update(int p,int x,int y,int s){
    if(x<=tree[p].l && y>=tree[p].r){//包含
        tree[p].val+=(long long)s*(tree[p].r-tree[p].l+1);
        tree[p].laz+=s;
        return;
    }
    pushdown(p);
    int mid=(tree[p].l+tree[p].r)/2;
    if(y<=mid){
        update(p<<1,x,y,s);
    }else if(x > mid){
        update(p<<1|1,x,y,s);
    }else{
        update(p<<1,x,mid,s);
        update(p<<1|1,mid+1,y,s);
    }
    tree[p].val = tree[p<<1].val + tree[p<<1|1].val;
}

long long query(int p,int x,int y){
    if(x<=tree[p].l && y>=tree[p].r){
        return tree[p].val;
    }
    pushdown(p);
    long long ans=0;
    int mid=(tree[p].l+tree[p].r)/2;
    
    if(y<=mid){
        ans += query(p<<1,x,y);
    }else if(x > mid){
        ans += query(p<<1|1,x,y);
    }else{
        ans += query(p<<1,x,mid);
        ans += query(p<<1|1,mid+1,y);
    }

    return ans;
    
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int q,x,y,z;
        scanf("%d",&q);
        if(q==1){
            scanf("%d%d%d",&x,&y,&z);
            update(1,x,y,z);
        }
        else {
            scanf("%d%d",&x,&y);
            cout<<query(1,x,y)<<endl;
        }
    }
    return 0;
}

先更新到这,时间不早,下次有时间继续更新

posted @ 2019-03-18 19:51  Fylsea  阅读(196)  评论(0编辑  收藏  举报