hdu-1166 敌兵布阵(线段树的增删查改)

这是我写的第一个线段树题,这种题过程很抽象,代码不容易理解,整整写了三小时,修BUG修了很久,不过还好过了。

思路:这个有点像二分的思想,根节点就是全部兵营,下来的第一个左子结点是全部兵的左半,右子节点是剩下的一半,经过重重递归二分,递归的边界就是只剩一个元素,即左子节点等于右子节点,这样,线段树就构造完成了,增删查改都是通过遍历来找到特定区间或元素,再改变它的值。


下面附上AC代码:

#include<cstdio>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
const int N=5e4+10;
int str[N];
int m,n;
int s;

struct tree
{
    int sum,l,r;
}node[N*4];

void build_tree(int ans,int ll,int rr)//ans是根节点!!!
{
    if( ll == rr )
    {
        node[ans].l = node[ans].r = ll;
        node[ans].sum = str [ll];
        return ;
    }
    node[ans].l = ll;
    node[ans].r = rr;
    //printf("Z");
    int mid = (ll + rr )>>1;
    //printf("C");
    build_tree(ans<<1,ll,mid);
    build_tree(ans<<1|1,mid+1,rr);
    node[ans].sum = node [ans<<1].sum + node[ans<<1|1].sum ;
}

void update(int ans,int pos,int value)//更新数值
{
    if(node[ans].l == pos && node[ans].r == pos)
    {
        node[ans].sum += value ;
        return ;
    }
    int mid = (node[ans].l+node[ans].r)>>1;
    if(pos <= mid)
    {
        update(ans<<1,pos,value);
    }
    else
    {
        update(ans<<1|1,pos,value);
    }

    node[ans].sum = node[ans<<1].sum + node[ans<<1|1].sum ;
}

void query(int ans,int ll,int rr)
{
    int mid = (node[ans].l+node[ans].r)>>1;
    if(node[ans].l == ll && node[ans].r == rr)
    {
        s += node[ans].sum;
        return ;
    }
    else if( ll > mid )
    {
        query(ans<<1|1,ll,rr);
    }
    else if( rr <= mid )
    {
        query(ans<<1,ll,rr);
    }
    else
    {
        query(ans<<1,ll,mid);
        query(ans<<1|1,mid+1,rr);
    }
}

int main()
{
    int t,x,y;
    int cas=0;
    char ch[10];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            scanf("%d",&str[i]);
        printf("Case %d:\n",++cas);
        build_tree(1,1,m);

        while(~scanf("%s",ch),ch[0]!='E')
        {
            scanf("%d%d",&x,&y);
            if(ch[0] == 'A')
            {
                update(1,x,y);
                //printf("A");
            }
            else if(ch[0] == 'S')
            {
               // printf("S");
                update(1,x,-y);
            }
            else if(ch[0] == 'Q')
            {
                s=0;
                //printf("Q");
                query(1,x,y);
                printf("%d\n",s);
            }
        }
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值