/*
*/
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【模板】线段树-区间修改

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

区间修改

大概思路:

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

————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\n",ans);
            ans=0;
        }
   }
    return 0;
}

(RP++!!)

 

posted @ 2019-09-22 19:13  Kyoko_Yosa  阅读(309)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end