线段树(单点更新与区域更新)

线段树

实在不好意思不写了哈哈哈啊哈。
线段树主要是解决一些大量操作区间并且维护区间的题目(维护的区间要有加和性)。
线段树核心函数有以下几个

  1. pushup()(主要用来向上跟新节点信息)
  2. pushdown()(用来向下更新来不及更新的节点)
  3. query()(查询当前区间的维护值)
  4. updata()(更新一个区域或者一个点的信息)
    注意
    单点更新是不需要pushdown函数的,并且维护信息里面没有lazy标记(具体会在区间更新里面详细叙述),而且线段树尽量用scanf和printf更快。
    不多说放题!!!
    hdu 1166 戳这里
    这是一道典型的区间单点更新问题,只需要找到根节点并且修改值,并且用pushup()传到树顶就行。但是值得注意的是线段树的题目一般操作次数很多,数据有的时候很大,用long long int存比较好,而且线段树的数组需要开到区域的4倍大小,不然很容易runtime!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<iomanip>
#define MAXN 50000
using namespace std;
#define ll long long int
struct node{
    ll key;
    ll lazy; 
};
node p[4*MAXN];
ll num[4*MAXN];
ll q=1,n;
void pushup(node p[],ll n)
{
    p[n].key=p[2*n].key+p[2*n+1].key;
}
void buildtree(node p[],ll n,ll l,ll r)
{    p[n].lazy=0;
    if(l==r)
      {   p[n].key=num[q];
           q++;
        return ;
       } 
    ll mid=(l+r)/2;
    buildtree(p,2*n,l,mid);
    buildtree(p,2*n+1,mid+1,r);
    pushup(p,n);
}
void pushdown(node p[],ll n,ll l,ll r)
{
    if(l!=r)
    {     ll mid=(r+l)/2;
        p[2*n].lazy=p[n].lazy;
        p[2*n].key=(mid-l+1)*p[2*n].lazy;
        p[2*n+1].lazy=p[n].lazy;
        p[2*n+1].key=(r-mid)*p[2*n+1].lazy;
    }
    p[n].lazy=0;
}
void updata(node p[],ll n,ll l,ll r,ll i,ll c)
{    ll mid=(l+r)/2;
      if(l==r&&l==i)
      {
        p[n].key+=c;
        return ;
       } 
       if(i<=mid)
      updata(p,2*n,l,mid,i,c);
      else
      updata(p,2*n+1,mid+1,r,i,c);
      if(l!=r)
      pushup(p,n);
}
ll query(node p[],ll n,ll l,ll r,ll x,ll y)
{
    if(l==x&&r==y)
       return p[n].key;
    if(p[n].lazy)
    pushdown(p,n,l,r);
    ll mid=(l+r)/2;
    if(y<=mid)
      return query(p,2*n,l,mid,x,y);
    else if(x>mid)
      return query(p,2*n+1,mid+1,r,x,y);
      else
      return query(p,2*n,l,mid,x,mid)+query(p,2*n+1,mid+1,r,mid+1,y);
}
int main()
{   
    ll t;
    ll w;
    scanf("%lld",&t);
    w=t;
    while(t--)
    {    q=1;
        ll n;
        scanf("%lld",&n);
        for(ll i=1;i<=n;i++)
        {
            ll a;scanf("%lld",&a);
            num[i]=a;
        }
        buildtree(p,1,1,n);
    printf("Case %lld:\n",w-t);
        string s;
        while(cin>>s)
        {
            if(s=="End")
            break;
            if(s=="Query")
             {
                ll i,j;
                scanf("%lld%lld",&i,&j);
                printf("%lld\n",query(p,1,1,n,i,j));
             }
             if(s=="Sub")
               {
                ll i,j;
                scanf("%lld%lld",&i,&j);
                updata(p,1,1,n,i,-1*j);
               }
               if(s=="Add")
               {
                ll i,j;
                scanf("%lld%lld",&i,&j);
                updata(p,1,1,n,i,j);
               }
        }
    }   
}

区间更新

区间跟新的题目比比单点更新稍微多一点东西,比如pushdown函数和lazy标记。
首先 lazy标记有什么用处?
由于线段树的大量操作,所以全部更新到树根未免太浪费时间了,所以我们用lazy标记保存住这个更新结果,如果我们下次访问需要更新到这个区间以下,再去用pushdown()更新。
hdu 1698 戳这里

#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<iomanip>
using namespace std;
#define MAXN 200000
#define ll long long int
struct node{
    ll key;
    ll lazy;
};
node p[4*MAXN];
ll q,n;
void pushup(node p[],ll n)
{
    p[n].key=p[2*n].key+p[2*n+1].key;
}
void buildtree(node p[],ll n,ll l,ll r)
{     p[n].lazy=0;
    if(l==r)
    {
        p[n].key=1;
        return ;
    }
    else
    {    ll mid=(l+r)/2;
        buildtree(p,2*n,l,mid);
        buildtree(p,2*n+1,mid+1,r);     
    }
    pushup(p,n);
    return ;
}
void pushdown(node p[],ll n,ll l,ll r)
{
    if(p[n].lazy)
    {   ll mid=(l+r)/2;
        p[2*n].lazy=p[n].lazy;
        p[2*n].key=p[2*n].lazy*(mid-l+1);
        p[2*n+1].lazy=p[n].lazy;
        p[2*n+1].key=(r-mid)*p[2*n+1].lazy;
    }
    p[n].lazy=0;
}
void updata(node p[],ll n,ll l,ll r,ll x,ll y,ll lazy)
{
    if(l==x&&r==y)
    {   p[n].lazy=lazy;
        p[n].key=(r-l+1)*p[n].lazy;
        return ;
    }
    if(p[n].lazy)
    pushdown(p,n,l,r);
    ll mid=(l+r)/2;
    if(x<=mid)
    updata(p,2*n,l,mid,x,min(y,mid),lazy);
    if(y>mid)
    updata(p,2*n+1,mid+1,r,max(x,mid+1),y,lazy);
    if(l!=r)
    pushup(p,n);

}
int query(node p[],ll n,ll l,ll r,ll x,ll y)
{    
    if(l==x&&r==y)
    {
        return p[n].key;
    }
    ll mid=(l+r)/2;

    if(y<=mid) return query(p,2*n,l,mid,x,y);
    else if(x>mid) return query(p,2*n+1,mid+1,r,x,y);
    else return query(p,2*n,l,mid,x,mid)+query(p,2*n+1,mid+1,r,mid+1,y);
}
int main()
{    int t;
    scanf("%d",&t);
    int w=t;
    while(t--)
    {    
        scanf("%lld%lld",&n,&q);
        buildtree(p,1,1,n); 
        for(ll i=1;i<=q;i++)
        {
            ll x,y,z;
            scanf("%lld%lld%lld",&x,&y,&z);
            updata(p,1,1,n,x,y,z);
        }
        printf("Case %d: The total value of the hook is %lld.\n",w-t,query(p,1,1,n,1,n));
    }
} 

记住好吗!!!!!!!!

猜你喜欢

转载自blog.csdn.net/wnmxhAC/article/details/81542110
今日推荐