您的位置:首页 > 其它

2017/9/21训练日记

2017-09-21 22:25 239 查看
看完了大体的线段树问题,有些难的跳过去了

总结一下,线段树解题步骤。

一:将问题转换成对点的统计问题。

二:将目标信息根据需要扩充成区间信息

1.增加信息符合区间加法。

2.增加标记支持区间操作。

三:代码中的主要模块:

1.区间加法 

2.标记下推 

3.点信息->区间信息 

4.操作(各种操作,包括修改和查询)

线段树5种基本操作代码:

#include<cstdio>

using namespace std;

int n,p,a,b,m,x,y,ans;

struct node

{

    int l,r,w,f;

}tree[400001];

inline void build(int k,int ll,int rr)//建树 

{

    tree[k].l=ll,tree[k].r=rr;

    if(tree[k].l==tree[k].r)

    {

        scanf("%d",&tree[k].w);

        return;

    }

    int m=(ll+rr)/2;

    build(k*2,ll,m);

    build(k*2+1,m+1,rr);

    tree[k].w=tree[k*2].w+tree[k*2+1].w;

}

inline void down(int k)//标记下传 

{

    tree[k*2].f+=tree[k].f;

    tree[k*2+1].f+=tree[k].f;

    tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);

    tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);

    tree[k].f=0;

}

inline 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)/2;

    if(x<=m) ask_point(k*2);

    else ask_point(k*2+1);

}

inline 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)/2;

    if(x<=m) change_point(k*2);

    else change_point(k*2+1);

    tree[k].w=tree[k*2].w+tree[k*2+1].w; 

}

inline 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)/2;

    if(a<=m) ask_interval(k*2);

    if(b>m) ask_interval(k*2+1);

}

inline void change_interval(int k)//区间修改 

{

    if(tree[k].l>=a&&tree[k].r<=b)

    {

        tree[k].w+=(tree[k].r-tree[k].l+1)*y;

        tree[k].f+=y;

        return;

    }

    if(tree[k].f) down(k);

    int m=(tree[k].l+tree[k].r)/2;

    if(a<=m) change_interval(k*2);

    if(b>m) change_interval(k*2+1);

    tree[k].w=tree[k*2].w+tree[k*2+1].w;

}

int main()

{

    scanf("%d",&n);//n个节点 

    build(1,1,n);//建树 

    scanf("%d",&m);//m种操作 

    for(int i=1;i<=m;i++)

    {

        scanf("%d",&p);

        ans=0;

        if(p==1)

        {

            scanf("%d",&x);

            ask_point(1);//单点查询,输出第x个数 

            printf("%d",ans);

        } 

        else if(p==2)

        {

            scanf("%d%d",&x,&y);

            change_point(1);//单点修改 

        }

        else if(p==3)

        {

            scanf("%d%d",&a,&b);//区间查询 

            ask_interval(1);

            printf("%d\n",ans);

        }

        else

        {

             scanf("%d%d%d",&a,&b,&y);//区间修改 

             change_interval(1);

        }

    }

}

//http://www.cnblogs.com/TheRoadToTheGold/p/6254255.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: