现在的位置: 首页 > 综合 > 正文

线段树 单点更新

2019年02月09日 ⁄ 综合 ⁄ 共 2985字 ⁄ 字号 评论关闭


线段数:

http://dongxicheng.org/structure/segment-tree/

http://hi.baidu.com/semluhiigubbqvq/item/be736a33a8864789f4e4ad18

http://www.notonlysuccess.com/index.php/segment-tree-complete/ 经典

单点更新:

hdu1166

#include<stdio.h>
#define MAXN 50000
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[MAXN<<2];
//maxn的取值 2^0+2^1+...+2^k(x^k>=n)=2^(k+1)-1>=maxn;
bool cmp(int x,int y)
{
    return x<y;
}
//向上
void PushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
//建树,由子节点确定根节点
void build(int l,int r,int rt)
{
    if(l==r)
    {
        scanf("%d",&sum[rt]);
        return ;
    }
    int m=(r+l)>>1;
    build(lson);
    build(rson);
    PushUp(rt);
}
//更新一个点,由子节点确定根节点
void update(int p,int add,int l,int r,int rt)
{
    //如果l==r,更新单点
    if(l==r)
    {
        sum[rt]+=add;
        return ;
    }
    //找p所在的范围
    int m=(l+r)>>1;
    if(m>=p) update(p,add,lson);
    else update(p,add,rson);
    PushUp(rt);
}
//询问,将所询问的断分成很多区间的和
int query(int L,int R,int l,int r,int rt)
{
    //l,r在所询问的范围内,则返回该段和
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int m=(l+r)>>1;
    int ret=0;
    //
    if(R>m)
        ret+=query(L,R,rson);
    if(L<=m)
        ret+=query(L,R,lson);
    return ret;
}
int main()
{
    int T,N,i;
    scanf("%d",&T);
    for(i=0; i<T; i++)
    {
        printf("Case %d:\n",i+1);
        scanf("%d",&N);
        build(1,N,1);
        char s[20];
        int a,b;
        while(scanf("%s",s)!=EOF)
        {
            if(s[0]=='E') break;

            scanf("%d%d",&a,&b);

            if(s[0]=='A')
            {
                update(a,b,1,N,1);
            }
            else if(s[0]=='S')
            {
                update(a,-b,1,N,1);
            }
            else
            {
                printf("%d\n",query(a,b,1,N,1));
            }
        }
    }
    return 0;
}

hdu1394

#include<stdio.h>
#define maxn 5555
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2];
int aa[maxn];
int min(int a,int b)
{
    return a>b?b:a;
}
//向上更新
void PushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
//建树
void build(int l,int r,int rt)
{
    sum[rt]=0;
    if(l==r)
    {
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
//更新
void update(int a,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]++;
        return ;
    }
    int m=(l+r)>>1;
    if(a<=m)
        update(a,lson);
    else
        update(a,rson);
    PushUp(rt);
}
//询问L到r共有多少个数
int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int ret=0;
    int m=(l+r)>>1;
    if(L<=m)
        ret+=query(L,R,lson);
    if(R>m)
        ret+=query(L,R,rson);
    return ret;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
        //建立空树
    {
        build(0,n-1,1);
        int sum0=0;
        for(int i=0; i<n; ++i)
        {
            scanf("%d",&aa[i]);
            //询问线段树中比a[i]大的数的个数;
            sum0+=query(aa[i]+1,n-1,0,n-1,1);
            //更新,插入a[i]这个点
            update(aa[i],0,n-1,1);
        }
        int ans=sum0;
        for(int i=0; i<n; ++i)
        {
            //将a[i]放到最后的逆序数,i从0到n-1
            //每次移动时,a[i]为第一个数,比a[i]小的数有a[i]个,比a[i]大的数有n-a[i]-1个;
            sum0=sum0-aa[i]+(n-aa[i]-1);
            ans=min(ans,sum0);
        }
        printf("%d\n",ans);
    }
    return 0;
}

hdu2795

#include<stdio.h>
#define maxn 200005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int w;
int max[maxn<<2];

void PushUp(int rt)
{
    max[rt]=max[rt<<1]>max[rt<<1|1]?max[rt<<1]:max[rt<<1|1];
}

//建树,每个节点的值都为w
void build(int l,int r,int rt)
{
    max[rt]=w;
    if(l==r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
//询问加更新。从最小的节点询问能否可以减掉x,并返回x所放的位置
int query(int x,int l,int r,int rt)
{
    if(l==r)
    {
        max[rt]-=x;
        return l;//返回x所放的位置
    }
    int m=(l+r)>>1;
    int ret;
    if(max[rt<<1]>=x)
        ret=query(x,lson);//返回x所放的位置
    else
        ret=query(x,rson);//返回x所放的位置
    PushUp(rt);
    return ret;//返回x所放的位置
}
int main()
{
    int h,n,x;
    while(scanf("%d%d%d",&h,&w,&n)!=EOF)
    {
        if(h>n)
            h=n;
        //建树,以1-h为区间长,w为每个节点的长度
        build(1,h,1);
        while(n--)
        {
            scanf("%d",&x);
            //从区间1-h询问每个节点是否能减掉x,如果可以滴话,更新树并输出
            //利用最大堆的性质
            if(max[1]<x)
                printf("-1\n");
            else
                printf("%d\n",query(x,1,h,1));
        }
    }
    return 0;
}




【上篇】
【下篇】

抱歉!评论已关闭.