zoukankan      html  css  js  c++  java
  • 线段树基础与例题

    目录

    1.建树 

    2.单点的添加(修改)

    3.区间查询

    4.区间修改(带懒惰标记)

    5.区间查询(带懒惰标记)

    例题:

    A.HDU-1166 敌兵布阵

    B.HDU-1754 I Hate It

    C.HDU-1698 Just a Hook

    D.ZOJ-1601 Count the Colors

    E.POJ-3264 Balanced Lineup

    F.HDU-4027 Can you answer these queries? 


    本文章基本只提供模板,建议参考下(https://oi-wiki.org/ds/segment/),里面有详细解释。

    预处理(纯属为了写代码方便,线段树要多次用到这三个,每个代码前面带着这段就ok了):

    #define lson l,m,p<<1     
    #define rson m+1,r,p<<1|1
    void pushplus(int p)
    {
        a[p] = a[p<<1] + a [p<<1|1];  //即a[p]=a[p*2]+a[p*2+1]
    }

    1.建树 :

    void build(int l, int r, int p) {
      // 对 [l,r] 区间建树,当前根的编号为 p
      if (l == r) {
        cin>>a[p];
        return;
      }
      int m = (s + t) >> 1;
      build(lson), build(rson);
      // 递归对左右区间建树
      pushplus(p)

    2.单点的添加(修改):

    void update(int x,int y,int l,int r,int p)  //把x节点增加y(修改为y)
    {
        if(l==r){
            a[p]+=y;   //若是修改这段换成a[p]=y;
            return ;
        }
        int m=(l+r)>>1;
        if(x<=m)
            update(x,y,lson);
        else
            update(x,y,rson);
        pushplus(p);
    }

    3.区间查询:

    int query(int x,int y,int l,int r,int p)
    {
        if(x<=l&&r<=y)
            return a[p];
        int m=(l+r)>>1;
        int sum=0;
        if(x<=m)
            sum+=query(x,y,lson);
        if(y>m)
            sum+=query(x,y,rson);
        return sum;
    }

    4.区间修改(带懒惰标记)(下面代码为区间加上某个值,若是区间全部修改为某个值则把代码中+=全改为=即可):

    void update(int l, int r, int c, int s, int t, int p) {
      // [l,r] 为修改区间,c 为被修改的元素的变化量,[s,t] 为当前节点包含的区间,p
      // 为当前节点的编号
      if (l <= s && t <= r) {
        a[p] += (t - s + 1) * c, b[p] += c;
        return;
      }  // 当前区间为修改区间的子集时直接修改当前节点的值,然后打标记,结束修改
      int m = (s + t) / 2;
      if (b[p] && s != t) {
        // 如果当前节点的懒标记非空,则更新当前节点两个子节点的值和懒标记值
        a[p * 2] += b[p] * (m - s + 1), a[p * 2 + 1] += b[p] * (t - m);
        b[p * 2] += b[p], b[p * 2 + 1] += b[p];  // 将标记下传给子节点
        b[p] = 0;                                // 清空当前节点的标记
      }
      if (l <= m) update(l, r, c, s, m, p * 2);
      if (r > m) update(l, r, c, m + 1, t, p * 2 + 1);
      pushplus(p);
    }

    5.区间查询(带懒惰标记)(下面代码为区间修改时加上某个值,若是修改时区间全部修改为某个值则把代码中除了sum后面的+=全改为=即可):

    int getsum(int l, int r, int s, int t, int p) {
      // [l,r] 为修改区间,c 为被修改的元素的变化量,[s,t] 为当前节点包含的区间,p
      // 为当前节点的编号
      if (l <= s && t <= r) return d[p];
      // 当前区间为询问区间的子集时直接返回当前区间的和
      int m = (s + t) / 2;
      if (b[p]) {
        // 如果当前节点的懒标记非空,则更新当前节点两个子节点的值和懒标记值
        a[p * 2] += b[p] * (m - s + 1), a[p * 2 + 1] += b[p] * (t - m),
            b[p * 2] += b[p], b[p * 2 + 1] += b[p];  // 将标记下传给子节点
        b[p] = 0;                                    // 清空当前节点的标记
      }
      int sum = 0;
      if (l <= m) sum += getsum(l, r, s, m, p * 2);
      if (r > m) sum += getsum(l, r, m + 1, t, p * 2 + 1);
      return sum;
    }

    例题:

    A.HDU-1166 敌兵布阵:简单的单点模板题,AC题解:

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <ctype.h>
    #include <cstring>
    #include <cstdio>
    #include <sstream>
    #include <cstdlib>
    #include <iomanip>
    #include <string>
    #include <queue>
    #include <map>
    #define M 50005
    #define ll long long
    #define lson l,m,p<<1
    #define rson m+1,r,p<<1|1
    using namespace std;
    const int maxn = 1e6+10;
    const int INF=0xfffffff;
    int a[M<<2];
    
    void pushplus(int rt)
    {
        a[rt] = a[rt<<1] + a [rt<<1|1];
    }
    void buide(int l,int r,int p)
    {
        if(l==r){
            scanf("%d",&a[p]);
            return ;
        }
        int m=(l+r)>>1;
        buide(lson);
        buide(rson);
        pushplus(p);
    }
    void update(int x,int y,int l,int r,int p)
    {
        if(l==r){
            a[p]+=y;
            return ;
        }
        int m=(l+r)>>1;
        if(x<=m)
            update(x,y,lson);
        else
            update(x,y,rson);
        pushplus(p);
    }
    int query(int x,int y,int l,int r,int p)
    {
        if(x<=l&&r<=y)
            return a[p];
        int m=(l+r)>>1;
        int sum=0;
        if(x<=m)
            sum+=query(x,y,lson);
        if(y>m)
            sum+=query(x,y,rson);
        return sum;
    }
    int main()
    {
        int t,x,y;
        int T=1;
        cin>>t;
        while(t--){
            printf("Case %d:
    ",T++);
            int n;
            cin>>n;
            buide(1,n,1);
            char str[20];
            while(cin>>str&&str[0]!='E'){
                cin>>x>>y;
                if(str[0]=='A')
                    update(x,y,1,n,1);
                else if(str[0]=='S')
                    update(x,-y,1,n,1);
                else if(str[0]=='Q'){
                    cout<<query(x,y,1,n,1)<<endl;
                }
            }
        }
        return 0;
    }

    B.HDU-1754 I Hate It:只需更换下父节点与子节点的关系即(a[p] = max(a[p<<1] , a [p<<1|1]),AC题解:

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <ctype.h>
    #include <cstring>
    #include <cstdio>
    #include <sstream>
    #include <cstdlib>
    #include <iomanip>
    #include <string>
    #include <queue>
    #include <map>
    #define M 50005
    #define ll long long
    #define lson l,m,p<<1
    #define rson m+1,r,p<<1|1
    using namespace std;
    const int maxn = 1e6+10;
    const int INF=0xfffffff;
    const int maxx=200005;
    int a[maxx*4];
    void pushplus(int rt)
    {
        a[rt] = max(a[rt<<1] , a [rt<<1|1]);
    }
    void build(int l,int r,int p)
    {
        if(l==r)
        {
            scanf("%d",&a[p]);
            return ;
        }
        int mid=(l+r)/2;
        build(l,mid,p*2);
        build(mid+1,r,p*2+1);
        pushplus(p);
    }
    void update(int x,int y,int l,int r,int p)
    {
        if(l==r){
            a[p]=y;
            return ;
        }
        int m=(l+r)>>1;
        if(x<=m)
            update(x,y,lson);
        else
            update(x,y,rson);
        pushplus(p);
    }
    int query(int x,int y,int l,int r,int p)
    {
        if(x<=l&&r<=y)
            return a[p];
        int m=(l+r)>>1;
        int sum=0;
        if(x<=m)
            sum=max(query(x,y,lson),sum);
        if(y>m)
            sum=max(query(x,y,rson),sum);
        return sum;
    }
    int main()
    {
        int n,t,x,y;
        while(scanf("%d%d",&n,&t)!=EOF){
            build(1,n,1);
            while(t--){
               char str;
               scanf(" %c %d %d",&str,&x,&y);
               if(str=='U')
                   update(x,y,1,n,1);
               else
                    printf("%d
    ",query(x,y,1,n,1));
            }
        }
        return 0;
    }

    C.HDU-1698 Just a Hook:区间修改的模板题,只需注意数据类型即可,AC题解:

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <ctype.h>
    #include <cstring>
    #include <cstdio>
    #include <sstream>
    #include <cstdlib>
    #include <iomanip>
    #include <string>
    #include <queue>
    #include <map>
    #define M 50005
    #define LL long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    const long long maxn = 2e5+5;
    const int INF=0xfffffff;
    const int maxx=200005;
    long long sum[maxx<<2],ad[maxx<<2];
    void pushup(long long rt)
    {
        sum[rt] = sum[rt<<1] + sum [rt<<1|1];
    }
    void build(long long l,long long r,long long rt)
    {
        ad[rt]=0;
        if(l==r)
        {
            sum[rt]=1;
            return ;
        }
        long long m=(l+r)>>1;
        build(lson);
        build(rson);
        pushup(rt);
    }
    void update(long long L,long long R,long long c,long long l,long long r,long long rt)
    {
        if(L<=l&&R>=r){
            ad[rt]=c;
            sum[rt]=(r-l+1)*c;
            return ;
        }
        long long m=(l+r)>>1;
        if(ad[rt]){
            sum[rt*2]=ad[rt]*(m-l+1);  sum[rt*2+1]=ad[rt]*(r-m);
            ad[rt*2]=ad[rt]; ad[rt*2+1]=ad[rt];
            ad[rt]=0;
        }
        if(L<=m)
            update(L,R,c,lson);
        if(R>m)
            update(L,R,c,rson);
        pushup(rt);
    }
    int main()
    {
        int kase=0;
        long long q,n,t,c,x,y;
        cin>>t;
        while(t--){
            cin>>n>>q;
            build(1,n,1);
            while(q--){
                scanf("%lld %lld %lld",&x,&y,&c);
                update(x,y,c,1,n,1);
            }
            printf("Case %d: The total value of the hook is %d.
    ",++kase , sum[1]);
        }
        return 0;
    }

    D.ZOJ-1601 Count the Colors:区间染色问题,AC题解:

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <ctype.h>
    #include <cstring>
    #include <cstdio>
    #include <sstream>
    #include <cstdlib>
    #include <iomanip>
    #include <string>
    #include <queue>
    #include <map>
    #define M 50005
    #define LL long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    using namespace std;
    const long long maxn = 2e5+5;
    const int INF=0xfffffff;
    const int maxx=200005;
    long long num[maxx<<2],ad[maxx<<2];
    int nad;
    void update(long long L,long long R,long long c,long long l,long long r,long long rt)
    {
        if(L<=l&&R>=r){
            ad[rt]=c;
            return ;
        }
        long long m=(l+r)>>1;
        if(ad[rt]!=-1){
            ad[rt*2]=ad[rt]; ad[rt*2+1]=ad[rt];
            ad[rt]=-1;
        }
        if(L<=m)
            update(L,R,c,lson);
        if(R>m)
            update(L,R,c,rson);
    }
    void query(long long l,long long r,long long rt)
    {
        if(l==r){
            if(ad[rt]>=0&&ad[rt]!=nad)
                num[ad[rt]]++;
            nad=ad[rt];
            return ;
        }
        long long m=(l+r)>>1;
        if(ad[rt]!=-1){
            ad[rt*2]=ad[rt]; ad[rt*2+1]=ad[rt];
            ad[rt]=-1;
        }
            query(lson);
            query(rson);
    }
    int main()
    {
        long long n,x,y,c;
        while(scanf("%lld",&n)!=-1){
            nad=-1;
            memset(num,0,sizeof(num));
            memset(ad,-1,sizeof(ad));
            for(int i=1;i<=n;i++){
                scanf("%lld%lld%lld",&x,&y,&c);
                if(x<y)
                update(x+1,y,c,1,8000,1);
            }
            query(1,8000,1);
            for(int i=0;i<=8000;i++){
                if(num[i]) printf("%d %lld
    ",i,num[i]);
            }
            printf("
    ");
    
        }
        return 0;
    }

    E.POJ-3264 Balanced Lineup:基础模板题,AC题解:

    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #include <ctype.h>
    #include <cstring>
    #include <cstdio>
    #include <sstream>
    #include <cstdlib>
    #include <iomanip>
    #include <string>
    #include <queue>
    #include <map>
    #define M 50005
    #define ll long long
    #define lson l,m,p<<1
    #define rson m+1,r,p<<1|1
    using namespace std;
    const int maxn = 1e6+10;
    const int INF=0xfffffff;
    const int maxx=200005;
    int a[maxx*4],b[maxx*4];
    void pushplus(int rt)
    {
        a[rt] = max(a[rt<<1] , a [rt<<1|1]);
    }
    void pushplus1(int rt)
    {
        b[rt] = min(b[rt<<1] , b [rt<<1|1]);
    }
    void build(int l,int r,int p)
    {
        if(l==r)
        {
            scanf("%d",&a[p]);
            b[p]=a[p];
            return ;
        }
        int mid=(l+r)/2;
        build(l,mid,p*2);
        build(mid+1,r,p*2+1);
        pushplus(p);
        pushplus1(p);
    }
    int query(int x,int y,int l,int r,int p)
    {
        if(x<=l&&r<=y)
            return a[p];
        int m=(l+r)>>1;
        int sum=0;
        if(x<=m)
            sum=max(query(x,y,lson),sum);
        if(y>m)
            sum=max(query(x,y,rson),sum);
        return sum;
    }
    int query1(int x,int y,int l,int r,int p)
    {
        if(x<=l&&r<=y)
            return b[p];
        int m=(l+r)>>1;
        int sum=INF;
        if(x<=m)
            sum=min(query1(x,y,lson),sum);
        if(y>m)
            sum=min(query1(x,y,rson),sum);
        return sum;
    }
    int main()
    {
        int n,m,x,y;
        scanf("%d%d",&n,&m);
        build(1,n,1);
        while(m--){
               scanf("%d %d",&x,&y);
               printf("%d
    ",query(x,y,1,n,1)-query1(x,y,1,n,1));
        }
        return 0;
    }

    F.HDU-4027 Can you answer these queries? :本题需要一点优化技巧。在进行更新操作的时候,由于是开根号取整,1开根号是其本身,所以在每个子区间进行更新时,特判一下会快很多(这个优化非常重要),避免超时。AC题解:

    #include<bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    const int maxn=1e5+5;
    typedef long long ll;
    ll sum[maxn<<2];
    void PushUP(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
     
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            scanf("%lld",&sum[rt]);
            return ;
        }
        int m=(l+r)>>1;
        build(lson);
        build(rson);
        PushUP(rt);
    }
    void update(int L,int R,int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]=sqrt(sum[rt]);
            return ;
        }
        if(L<=l&&R>=r&&sum[rt]==r-l+1)//如果区间内的所有数都是1则不必更新
            return;
        int m=(l+r)>>1;
        if(L<=m)
            update(L,R,lson);
        if(m<R)
            update(L,R,rson);
        PushUP(rt);
    }
    ll query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            return sum[rt];
        }
        int m=(l+r)>>1;
        ll ret=0;
        if(L<=m)
            ret+=query(L,R,lson);
        if(R>m)
            ret+=query(L,R,rson);
        return ret;
    }
    int main()
    {
        int n,m,t=0;
        while(scanf("%d",&n)==1)
        {
            int a,b,c;
            build(1,n,1);
            scanf("%d",&m);
            printf("Case #%d:
    ",++t);
            while(m--)
            {
                scanf("%d%d%d",&a,&b,&c);
                if(b>c) swap(b,c);
                if(a)
                    printf("%lld
    ",query(b,c,1,n,1));
                else
                    update(b,c,1,n,1);
            }
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    -bash: fork: Cannot allocate memory 问题的处理
    Docker top 命令
    docker常见问题修复方法
    The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
    What's the difference between encoding and charset?
    hexcode of é î Latin-1 Supplement
    炉石Advanced rulebook
    炉石bug反馈
    Sidecar pattern
    SQL JOIN
  • 原文地址:https://www.cnblogs.com/shmilky/p/14089057.html
Copyright © 2011-2022 走看看