邂逅 數據結構

              1、線段樹html

http://www.cnblogs.com/TheRoadToTheGold/p/6254255.htmlnode

一、建樹,即創建一棵線段樹ios

   主體思路:a、對於二分到的每個結點,給它的左右端點肯定範圍。ide

                     b、若是是葉子節點,存儲要維護的信息。ui

                     c、狀態合併。spa

void build(int k,int l,int r)//建樹 
{
    tree[k].l=l,tree[k].r=r;
    if(tree[k].l==tree[k].r)
    {
        tree[k].w=read();
        return ;
    }
    int m=(l+r)>>1;
    build(k<<1,l,m);
    build(k<<1|1,m+1,r);
    tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
建樹

二、單點查詢,即查詢一個點的狀態,設待查詢點爲xcode

  主體思路:與二分查詢法基本一致,若是當前枚舉的點左右端點相等,即葉子節點,就是目標節點。若是不是,由於這是二分法,因此設查詢位置爲x,當前結點區間範圍爲了l,r,中點爲         mid,則若是x<=mid,則遞歸它的左孩子,不然遞歸它的右孩子htm

void ask(int k)
{
    if(tree[k].l==tree[k].r) //當前結點的左右端點相等,是葉子節點,是最終答案 
    {
        ans=tree[k].w;
        return ;
    }
    int m=(tree[k].l+tree[k].r)/2;
    if(x<=m) ask(k*2);//目標位置比中點靠左,就遞歸左孩子 
    else ask(k*2+1);//反之,遞歸右孩子 
}
單點查詢

三、單點修改,即更改某一個點的狀態。用引例中的例子,對第x個數加上yblog

主體思路  結合單點查詢的原理,找到x的位置;根據建樹狀態合併的原理,修改每一個結點的狀態。遞歸

void change_point(int k)//單點修改 
{
    if(tree[k].l==tree[k].r)
    {
        tree[k].w+=y;
        return ;
    }
    if(tree[k].f) down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(x<=m) change_point(k<<1);
    else change_point(k<<1|1);
    tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
單點修改

4.區間修改+區間查詢

void change_interval(int k)//區間修改 
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        tree[k].w+=y*(tree[k].r-tree[k].l+1);
        tree[k].f+=y;
        return ;
    }
    if(tree[k].f) down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(a<=m) change_interval(k<<1);
    if(b>m)  change_interval(k<<1|1);
    tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
void ask_interval(int k)//區間查詢 
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        ans+=tree[k].w;
        return ;
    }
    if(tree[k].f) down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(a<=m) ask_interval(k<<1);
    if(b>m)  ask_interval(k<<1|1);
}
區間修改+區間查詢

5.標記下傳

實現思路

           a.原結構體中增長新的變量,存儲這個懶標記。

           b.遞歸到這個節點時,只更新這個節點的狀態,並把當前的更改值累積到標記中。注意是累積,能夠這樣理解:過年,不少個親戚都給你壓歲錢,但你暫時不用,因此都被你父母扣下了。

           c.何時纔用到這個懶標記?當須要遞歸這個節點的子節點時,標記下傳給子節點。這裏沒必要管用哪一個子節點,兩個都傳下去。就像你若是還有妹妹,父母給大家零花錢時總不能偏愛吧

           d.下傳操做:

               3部分:①當前節點的懶標記累積到子節點的懶標記中。

                         ②修改子節點狀態。在引例中,就是原狀態+子節點區間點的個數*父節點傳下來的懶標記

void down(int k)//標記下傳 
{
    tree[k<<1].f+=tree[k].f;
    tree[k<<1|1].f+=tree[k].f;
    tree[k<<1].w+=tree[k].f*(tree[k<<1].r-tree[k<<1].l+1);
    tree[k<<1|1].w+=tree[k].f*(tree[k<<1|1].r-tree[k<<1|1].l+1);
    tree[k].f=0;
}
標記下傳
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 4000001
using namespace std;
long long ans;
int n,m,q,x,y,a,b;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct Tree
{
    int l,r,f;long long w;
}tree[N];
void build(int k,int l,int r)//建樹 
{
    tree[k].l=l,tree[k].r=r;
    if(tree[k].l==tree[k].r)
    {
        tree[k].w=read();
        return ;
    }
    int m=(l+r)>>1;
    build(k<<1,l,m);
    build(k<<1|1,m+1,r);
    tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
void down(int k)//標記下傳 
{
    tree[k<<1].f+=tree[k].f;
    tree[k<<1|1].f+=tree[k].f;
    tree[k<<1].w+=tree[k].f*(tree[k<<1].r-tree[k<<1].l+1);
    tree[k<<1|1].w+=tree[k].f*(tree[k<<1|1].r-tree[k<<1|1].l+1);
    tree[k].f=0;
}
void change_point(int k)//單點修改 
{
    if(tree[k].l==tree[k].r)
    {
        tree[k].w+=y;
        return ;
    }
    if(tree[k].f) down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(x<=m) change_point(k<<1);
    else change_point(k<<1|1);
    tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
void ask_point(int k)//單點查詢 
{
    if(tree[k].l==tree[k].r)
    {
        ans=tree[k].w;
        return ;
    }
    if(tree[k].f) down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(x<=m) ask_point(k<<1);
    else ask_point(k<<1|1);
}
void change_interval(int k)//區間修改 
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        tree[k].w+=y*(tree[k].r-tree[k].l+1);
        tree[k].f+=y;
        return ;
    }
    if(tree[k].f) down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(a<=m) change_interval(k<<1);
    if(b>m)  change_interval(k<<1|1);
    tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}
void ask_interval(int k)//區間查詢 
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        ans+=tree[k].w;
        return ;
    }
    if(tree[k].f) down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(a<=m) ask_interval(k<<1);
    if(b>m)  ask_interval(k<<1|1);
}
int main()
{
    n=read();m=read();
    build(1,1,n);
    while(m--)
    {
        q=read();ans=0;
        if(q==1)
        {
            a=read(),b=read(),y=read();
            change_interval(1);
        }
        else
        {
            a=read(),b=read();
            ask_interval(1);
            printf("%lld\n",ans);
        }
    }
    return 0;
}
線段樹5個操做代碼
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100005
using namespace std;
int n,m,c,a,b,x;
long long ans,minn;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct Tree
{
    int l,r;
    long long w,f;
}tree[N<<2];
struct Node
{
    int x,y,z;
}node[N];
int cmp(Node a,Node b)
{
    return a.y<b.y;
}
void build(int k,int l,int r)
{
    tree[k].l=l,tree[k].r=r;
    if(tree[k].l==tree[k].r)
    {
        tree[k].w=c;
        return ;
    }
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tree[k].w=min(tree[k<<1].w,tree[k<<1|1].w);
}
void down(int k)
{
    tree[k<<1].f+=tree[k].f;
    tree[k<<1|1].f+=tree[k].f;
    tree[k<<1].w+=tree[k].f;
    tree[k<<1|1].w+=tree[k].f;
    tree[k].f=0;
}
void change(int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        tree[k].w+=x;
        tree[k].f+=x;
        return ;
    }
    if(tree[k].f) down(k); 
    int mid=(tree[k].r+tree[k].l)>>1;
    if(a<=mid) change(k<<1);
    if(b>mid)  change(k<<1|1);
    tree[k].w=min(tree[k<<1].w,tree[k<<1|1].w);
}
void ask(int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        minn=min(minn,tree[k].w);
        return ;
     } 
    if(tree[k].f) down(k);
    int mid=(tree[k].r+tree[k].l)>>1;
    if(a<=mid) ask(k<<1);
    if(b>mid)  ask(k<<1|1);
}
int main()
{
    m=read(),n=read(),c=read();
    build(1,1,n);
    for(int i=1;i<=m;i++) 
    {
        node[i].x=read(),node[i].y=read();
        node[i].z=read();node[i].y--;
    } 
    sort(node+1,node+1+m,cmp);
    for(int i=1;i<=m;i++)
    {
        a=node[i].x,b=node[i].y;
        minn=0x7fffffff;ask(1);
        if(minn>node[i].z) x=-node[i].z,change(1),ans+=node[i].z;
        else x=-minn,change(1),ans+=minn;
    }
    printf("%lld",ans);
}
區間求最小值
相關文章
相關標籤/搜索