zoukankan      html  css  js  c++  java
  • 【模板】线段树-区间修改

    与上篇线段树一起食用效果更佳:神奇线段树(点击收获幸福)

    区间修改

    大概思路:

    一开始当然是暴力!(会超时的否掉)不用暴力的话。。就用

    ————Lazy标记 :是一个延迟标记,先给最大的区间加上一个标记,下一次遇到时再执行,并同时下放标记。

    (结合代码了解吧。。我不想画图。。。)

    先建树

    //建树 
    void build_tree(int x,int y,int p)
    {
        tree[p].a=x;
        tree[p].b=y;
        tree[p].maxx=tree[p].lazy=0;//初始化 
        if(x==y)
        {
            tree[p].maxx=a[x]; 
            return;
        }
        int mid=(x+y)/2;
        build_tree(x,mid,p*2);
        build_tree(mid+1,y,p*2+1);
        tree[p].maxx=max(tree[p*2].maxx,tree[p*2+1].maxx);//求最大值 
    } 

    区间修改

    //区间修改 
    void putdown(int p)
    {
        tree[p*2].maxx+=tree[p].lazy;
        tree[p*2].lazy+=tree[p].lazy;//将标记下放给左儿子 
        tree[p*2+1].maxx+=tree[p].lazy;
        tree[p*2+1].lazy+=tree[p].lazy;//下放给右儿子 
        tree[p].lazy=0;//将当前标记清零 
    }
    void changeplus(int x,int y,int p,int V)
    {
        if(!tree[p].lazy)
        putdown(p);//遇到标记就下放 
        if(x<=tree[p].a&&tree[p].b<=y)
        {
            tree[p].lazy+=V;
            tree[p].maxx+=V;//将当前的标记执行掉 
            return;
        }
        int mid=(tree[p].a+tree[p].b)/2;
        if(y<=tree[p*2].b)
        changeplus(x,mid,p*2,V);
        if(x>=tree[p*2+1].a)
        changeplus(mid+1,y,p*2+1,V);
        tree[p].maxx=max(tree[p*2].maxx,tree[p*2+1].maxx);//简单二分 
    } 
    void changeplus(int x,int y,int p,int V)
    {
        cout<<"当前节点"<<p<<endl; 
        if(x<=tree[p].a&&tree[p].b<=y)
        {
            tree[p].lazy+=V;
            tree[p].maxx+=V*(tree[p].b-tree[p].a+1);//将当前的标记执行掉 '
            cout<<"完全包含区间序号"<<p<<" "<<tree[p].maxx<<"懒标记"<<tree[p].lazy<<endl; 
            return;
        }
        if(tree[p].lazy)
        {
        putdown(p);
        cout<<"下放"<<endl;
        //遇到标记就下放 
        int mid=(tree[p].a+tree[p].b)/2;
        if(x<=mid&&y>=tree[p*2].a )changeplus(x,y,p*2,V);
        if(y>mid&&x<=tree[p*2+1].b)changeplus(x,y,p*2+1,V);
        tree[p].maxx=tree[p*2].maxx+tree[p*2+1].maxx;
        cout<<"更新节点值"<<p<<" "<<tree[p].maxx<<"懒标记"<<tree[p].lazy<<endl; 
        for(int i=1;i<=2*n-1;i++)
        {
              cout<<i<<" "<<tree[i].lazy<<" "<<endl; 
        } 
    } 

    查询区间最大值

    //查询最大值 
    int ask(int x,int y,int p)
    {
        if(!tree[p].lazy)
        putdown(p);//有标记就下放 
        if(x>=tree[p].a&&y<=tree[p].b)
        return tree[p].maxx;//所求区间在当前区间内 
        int L,R,mid;
        mid=(tree[p].a+tree[p].b)/2;
        if(y<=tree[p*2].b)//在左边 
        L=ask(x,y,p*2);
        if(x>=tree[p*2+1].a)//在右边 
        R=ask(x,y,p*2+1);
        return max(L,R);
    } 

    看道题吧(点击收获RP++)

    冥想ing。。。

    AC代码:

    (调了两天。。终于。。)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    struct node{
        int a,b;
        long long int lazy,maxx;
    }tree[4000004];
    int a[500005];
    long long int ans;
    //建树 
    void build_tree(int x,int y,int p)
    {
        tree[p].a=x;
        tree[p].b=y;
        tree[p].maxx=tree[p].lazy=0;//初始化 
        if(x==y)
        {
            tree[p].maxx=a[x]; 
            return;
        }
        int mid=(x+y)/2;
        build_tree(x,mid,p*2);
        build_tree(mid+1,y,p*2+1);
        tree[p].maxx=tree[p*2].maxx+tree[p*2+1].maxx;
    } 
    //区间修改 
    void putdown(int p)
    {
        tree[p*2].maxx+=tree[p].lazy*(tree[p*2].b-tree[p*2].a+1);
        tree[p*2].lazy+=tree[p].lazy;//将标记下放给左儿子 
        tree[p*2+1].maxx+=tree[p].lazy*(tree[p*2+1].b-tree[p*2+1].a+1);
        tree[p*2+1].lazy+=tree[p].lazy;//下放给右儿子 
        tree[p].lazy=0;//将当前标记清零 
    }
    void changeplus(int x,int y,int p,int V)
    {
        
        if(x<=tree[p].a&&tree[p].b<=y)//处理不是正好在区间里的 
        {
            tree[p].lazy+=V;
            tree[p].maxx+=V*(tree[p].b-tree[p].a+1);//将当前的标记执行掉 
            return;
        }
        if(tree[p].lazy)
        putdown(p);//遇到标记就下放 
        int mid=(tree[p].a+tree[p].b)/2;
        if(x<=mid&&y>=tree[p*2].a )changeplus(x,y,p*2,V);
        if(y>mid&&x<=tree[p*2+1].b)changeplus(x,y,p*2+1,V);
        tree[p].maxx=tree[p*2].maxx+tree[p*2+1].maxx;
    } 
    
    void ask(int x,int y,int p)
    {
        if(tree[p].lazy)
        putdown(p);
        if(x==tree[p].a&&y==tree[p].b)
        {
            ans=tree[p].maxx;
            return;
        }
        if(y<=tree[p*2].b)
        ask(x,y,p*2);
        if(x>=tree[p*2+1].a)
        ask(x,y,p*2+1);
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        int A,B,C,D;
    
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        build_tree(1,n,1);
        
        for(int i=1;i<=m;i++) 
        {
            scanf("%d",&A);
            if(A==1)
            {
                scanf("%d%d%d",&B,&C,&D);
                changeplus(B,C,1,D);
            }
            else
            {
                scanf("%d",&B);
                ask(B,B,1);
                printf("%lld
    ",ans);
                ans=0;
            }
       }
        return 0;
    }

    (RP++!!)

  • 相关阅读:
    sphinx实时索引和高亮显示
    打开页面就进行下载的一种方法
    mysql开启慢查询日志以及查看(转载自网络)
    Best MVC Practices(最优的MVC布局)
    nginx虚拟机配置(支持php)
    一个简单大方的赞后+1,踩后-1js动画效果
    如何创建ajax对象?
    psd图片到html
    小知识
    sass入门
  • 原文地址:https://www.cnblogs.com/Daz-Os0619/p/11537534.html
Copyright © 2011-2022 走看看