敌兵布阵 HDU - 1166(萌新谈线段树体会)

    对我个人而言,什么是线段树?就是将一个长长的大区间分为一段段小区间,然后,每段小区间按照某种方式分配了大区间里的值或者元素。

        上题之前讲一下怎么制造这个树?怎么初步的用这个树?这个树的功能。(因为初学,讲的会有点通熟易懂)

就像学软机的链表,二叉树一样,我们构造一个线段树也将用结构体类型去定义它:这个线段树需要有它在当前位置上的值,需要有它的区间段左右端点),同时如果它有子树的话,还需要用指针型分别指向它的左子树右子树

附上代码:

struct Tree
{
    int date;
    int left;
    int right;
    Tree *lchild;
    Tree *rchild;
};

接下来,我们既然有了树的模版就要创建树,怎样creat一个树,我们就需要理解线段树了,很多像我一样的萌新认识线段树应该都会从网上学到:如果根子树的区间为[a, b],那么它的左子树区间为[a,(a+b)/2],右子树区间为[(a+b)/2+1,b]。所以有的人用左子树[a,(a+b)>>1],右子树[(a+b)>>1+1,b]这样的骚操作表示(“>>”正数左移一位相当于对2整除)。当到叶子节点(即a==b,无子树时)的那个子树时,给予它附上值(也有时并非如此,此题需要而已)。

ps:提示,一定要用malloc()开内存,不然就会死掉,学习链表,二叉树等所带来的经验了。

我一开始malloc()没用对,导致我一直莫名其妙Wrong,因为sizeof()里一定要放类名。

附上代码:

Tree *creatTree(int a,int b)
{
    Tree *r;
    r=(Tree*)malloc(sizeof(Tree));
    r->left=a;
    r->right=b;
    if(a==b)
    {
        r->date=num[a];
        r->lchild=NULL;
        r->rchild=NULL;
    }
    else
    {
        int mid=(a+b)/2;
        r->lchild=creatTree(a, mid);
        r->rchild=creatTree(mid+1, b);
        r->date = r->lchild->date + r->rchild->date;
    }
    return r;
}

        接下来,我们要对这个已经初步成形的线段树进行操作,那么就得需要写些子函数了,为了使得形参的改变等同于实参的改变,我们必须用上指针,然后再逐步查找所对应的点,并对它进行操作。

void Tree_insert(Tree *r,int a,int b)
{
    if(r->left==a&&r->right==a)
    {
        r->date+=b;
        return;
    }
    int mid=(r->left+r->right)/2;
    if(a<=mid)
    {
        Tree_insert(r->lchild, a, b);
    }
    else
    {
        Tree_insert(r->rchild, a, b);
    }
    r->date+=b;
}

        接下来,我们需要一个查找函数,找到对应某个区间(a, b)的值。那么我们就会想,如果这个区间(a, b)不在那些个已经存在的区间怎么办?举个例子:大区间(1,5)它的子区间只有(1, 3), (4, 5), (1, 2), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)。假如我们需要找个(2,4)区间内的值岂不是没有办法?不会的,寻找区间(2,4)范围虽然不在这些个子区间段内,但它恰好可以用(2, 2), (3, 3), (4, 4)的和来表示,那么这样的问题就解决了。

void Tree_find(Tree *r,int a,int b)
{
    if(r->left==a&&r->right==b)
    {
        sum+=r->date;
        return;
    }
    int mid=(r->left+r->right)/2;
    if(a>mid)
    {
        Tree_find(r->rchild, a, b);
    }
    else if(b<=mid)
    {
        Tree_find(r->lchild, a, b);
    }
    else
    {
        Tree_find(r->lchild, a, mid);
        Tree_find(r->rchild, mid+1, b);
    }
}

        那么,这道题所需要的功能便齐全了,附上AC代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;
int num[50005];
int n;
int sum;
string work;
int st,en;
struct Tree
{
    int date;
    int left;
    int right;
    Tree *lchild;
    Tree *rchild;
};
Tree *creatTree(int a,int b)
{
    Tree *r;
    r=(Tree*)malloc(sizeof(Tree));
    r->left=a;
    r->right=b;
    if(a==b)
    {
        r->date=num[a];
        r->lchild=NULL;
        r->rchild=NULL;
    }
    else
    {
        int mid=(a+b)/2;
        r->lchild=creatTree(a, mid);
        r->rchild=creatTree(mid+1, b);
        r->date = r->lchild->date + r->rchild->date;
    }
    return r;
}
void Tree_insert(Tree *r,int a,int b)
{
    if(r->left==a&&r->right==a)
    {
        r->date+=b;
        return;
    }
    int mid=(r->left+r->right)/2;
    if(a<=mid)
    {
        Tree_insert(r->lchild, a, b);
    }
    else
    {
        Tree_insert(r->rchild, a, b);
    }
    r->date+=b;
}
void Tree_find(Tree *r,int a,int b)
{
    if(r->left==a&&r->right==b)
    {
        sum+=r->date;
        return;
    }
    int mid=(r->left+r->right)/2;
    if(a>mid)
    {
        Tree_find(r->rchild, a, b);
    }
    else if(b<=mid)
    {
        Tree_find(r->lchild, a, b);
    }
    else
    {
        Tree_find(r->lchild, a, mid);
        Tree_find(r->rchild, mid+1, b);
    }
}
int main()
{
    Tree *t;
    int T;
    scanf("%d%*c",&T);
    int ca=0;
    while(T--)
    {
        ca++;
        memset(num, 0, sizeof(num));
        printf("Case %d:\n",ca);
        scanf("%d%*c",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
        }
        t=creatTree(1, n);
        while(cin>>work&&work!="End")
        {
            if(work!="End")
            {
                cin>>st>>en;
                if(work=="Add")
                {
                    Tree_insert(t, st, en);
                }
                else if(work=="Sub")
                {
                    Tree_insert(t, st, -en);
                }
                else if(work=="Query")
                {
                    sum=0;
                    Tree_find(t, st, en);
                    printf("%d\n",sum);
                }
            }
            else break;
        }
    }
    return 0;
}

谢谢观看,欢迎评论留言。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值