邂逅 数据结构

              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);
}
区间求最小值
相关文章
相关标签/搜索