码迷,mamicode.com
首页 > 其他好文 > 详细

【模板】线段树

时间:2018-10-15 20:34:54      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:ISE   style   using   状态更新   数加   递归   ++   code   amp   

 

#include<bits/stdc++.h>
using namespace std;
int a,b,ans,n,m,x,y;

//点-结构体
struct node
{
    int l,r,w,f;
}tree[400001];

//建树 左孩子结点为2*k 右孩子为2k+1
void build(int l,int r,int k)
{
    tree[k].l=l;
    tree[k].r=r;
    if(tree[k].l==tree[k].r)//叶子结点
    {
        scanf("%d",&tree[k].w);
        return;
    }
    int mid=(l+r)/2;
    bulid(l,mid,k*2);    //左孩子
    build(mid+1,r,k*2+1);//右孩子
    tree[k].w=tree[k*2].w+tree[k*2+1].w;//状态合并,w为两个孩子w之和
}

//标记下传
//f 每个子节点要加的值
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;
}

//单点查询 待查询点位置为x 初始一般k=1
void askp(int k)
{
    if(tree[k].l==tree[k].r)//当前结点的左右端点相等,即是叶子节点(最终答案)
    {
        ans=tree[k].w;
        return;
    }
    if(tree[k].f)down(k);
    int mid=(tree[k].l+tree[k].r)/2;
    if(x<=mid)askp(k*2);//目标位置比中点靠左,则递归左孩子
    else askp(k*2+1);   //靠右,则递归右孩子
}

//单点修改 比如:对第x个数加上y
//revise 修改
void rep(int k)
{
    if(tree[k].l==tree[k].r)//找到目标位置
    {
        tree[k].w+=y;
        return;
    }
    if(tree[k].f)down(k);
    int mid=(tree[k].l+tree[k].r)/2;
    if(x<=mid)add(k*2);
    else add(k*2+1);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;//所有包含结点k的结点状态更新
}

//区间查询 区间[a,b]之和
//a<=mid,即查询区间全在当前区间的左子区间,递归左孩子
//b>mid。即查询区间全在当前区间的右子区间,递归右孩子
void askin(int k)
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        ans+=tree[k].w;
        return;
    }
    if(tree[k].f)down(k);
    int mid=(tree[k].l+tree[k].r)/2;
    if(a<=mid)askin(k*2);
    if(b>mid)askin(k*2+1);
}

//区间修改,即修改一段连续区间的值
void rein(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 mid=(tree[k].l+tree[k].r)/2;
    if(a<=mid)rein(k*2);
    if(b>mid)rein(k*2+1);
    tree[k].w=tree[k*2].w+tree[k*2+1].w;
}
int main()
{
    scanf("%d",&n);//n个节点
    build(n,1,1);//建树
    scanf("%d",&m);//m种操作
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&p);
        ans=0;
        if(p==1)
        {
            scanf("%d",&x);
            ap(1);//单点查询,输出第x个数
            printf("%d",ans);
        }
        else if(p==2)
        {
            scanf("%d%d",&x,&y);
            rep(1);//单点修改
        }
        else if(p==3)
        {
            scanf("%d%d",&a,&b);//区间查询
            askin(1);
            printf("%d\n",ans);
        }
        else
        {
             scanf("%d%d%d",&a,&b,&y);//区间修改
             rein(1);
        }
    }
    return 0;
}

 

【模板】线段树

标签:ISE   style   using   状态更新   数加   递归   ++   code   amp   

原文地址:https://www.cnblogs.com/kannyi/p/9792671.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!