【hdoj】1166 敌兵布阵【线段树--单点更新,区间求和】

传送门:1166 敌兵布阵

题意:

线段树,单点加或减,求区间和。
貌似应当是 用树状数组来做。

思路:

我的思路是参考了线段树 区间替换,区间求和 的代码。
单点加或减不就是长度为1的区间的替换吗?
但是Wrong Answer了,暂时也不想debug,只想快的过知识点和收集板子。

My Wrong Code And Online AC Code

/*
My Wrong Code
*/
#include <bits/stdc++.h>
using namespace std;

const int maxn=50005;

int sum[maxn<<2],flag[maxn<<2];
int A[maxn];
int index=0;
inline void PushUp(int idx)
{
    sum[idx]=sum[idx<<1]+sum[idx<<1|1];
}

void Build(int idx,int left,int right)
{
    // flag : -1表示没有懒惰标记
    flag[idx]=-1;
    if(left==right)
    {
        sum[idx]=A[index++];
        //scanf("%d",sum+idx);
        return ;
    }
    int mid=(left+right)>>1;
    Build(idx<<1,left,mid);
    Build(idx<<1|1,mid+1,right);
    PushUp(idx);
}

// 懒惰标记的‘下放操作’
inline void PushDown(int idx,int left,int mid)
{
    int L=idx<<1,R=L+1;
    sum[L]=(mid-left+1)*flag[idx];
    sum[R]=sum[idx]-sum[L];
    flag[L]=flag[R]=flag[idx];
    flag[idx]=-1;
}

int L,R,val;

void Update(int idx,int left,int right)
{
    if(L<=left && right<=R)
    {
        sum[idx]=(right-left+1)*val;
        // 放置懒惰标记
        flag[idx]=val;
        return;
    }
    int mid=(left+right)>>1;
    if(flag[idx]!=-1) PushDown(idx,left,mid);
    if(L<=mid) Update(idx<<1,left,mid);
    if(mid<R) Update(idx<<1|1,mid+1,right);
    PushUp(idx);
}

int Query(int idx,int left,int right)
{
    if(L<=left && right<=R)
        return sum[idx];
    int mid=(left+right)>>1,ans=0;
    if(flag[idx]!=-1) PushDown(idx,left,mid);
    if(L<=mid) ans+=Query(idx<<1,left,mid);
    if(mid<R) ans+=Query(idx<<1|1,mid+1,right);
    return ans;
}

int main()
{
    int t;
    scanf("%d",&t);
    for(int i=1; i<=t; i++)
    {
        printf("Case %d:\n",i);        
        //freopen("test.txt","r",stdin);
        int N,M;
        scanf("%d",&N);
        for(int i=0; i<N; i++)
        {
            scanf("%d",&A[i]);
        }
        Build(1,1,N);
        //scanf("%d",&M);
        while(true)
        {
            string s;
            cin>>s;
            if(s=="End")
                break;
            if(s=="Query")
            {
                scanf("%d%d",&L,&R);
                printf("%d\n",Query(1,1,N));
            }
            else if(s=="Add")
            {
                scanf("%d",&L);
                R=L;
                scanf("%d",&val);
                val=A[L-1]+val;
                Update(1,1,N);
            }
            else if(s=="Sub")
            {
                scanf("%d",&L);
                R=L;
                scanf("%d",&val);
                val=A[L-1]-val;
                Update(1,1,N);
            }            
        }
    }
    return 0;
}




/*
Online AC Code
单点更新,区间求和
参考:http://chuanwang66.iteye.com/blog/1418459
*/
#include <stdio.h>
#define lson l , m , rt << 1
//预定义lson为: l,m,rt<<1
//——凡是写lson的地方,替换为l,m,rt<<1,表示原节点的左儿子
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 55555;
int sum[maxn<<2];

void PushUP(int rt)
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    //sum[rt]=sum[rt/2]+sum[rt/2+1];
}

/*
    最外层调用build(1,n,1):
    下标1为根的子树表示线段范围是[1,n],且为离散型(整数点)
*/
void build(int l,int r,int rt)
{
    //递归结束条件:到达线段树叶子节点(编号rt),则可以输入其值
    if (l == r)
    {
        scanf("%d",&sum[rt]);   //之所以将rt作为输入,目的是在构造叶子节点的时候要用
        return ;
    }

    int m = (l + r) >> 1;
    build(lson);    //build(l,m,rt<<1);
    build(rson);    //build(m+1,r,rt<<1|1);
    PushUP(rt);
}

//线段树(单点/非区间)更新
void update(int p,int add,int l,int r,int rt)
{
    if (l == r)
    {
        sum[rt] += add;
        return ;
    }

    //下面采用分治法(之所以从中间劈开是为了逐渐减小问题规模)
    int m = (l + r) >> 1;
    if (p <= m) update(p, add, lson);    //#define lson l m rt<<1
    else update(p, add, rson);          //#define rson m+1 r rt<<1|1

    //回溯返回时,更新上层节点
    PushUP(rt);
}

//线段树查询
/*
    query a b对应
    query(a,b,1,n,1)
*/
int query(int L,int R,int l,int r,int rt)
{
    //递归结束条件:查询范围 比 线段子树范围宽
    if (L <= l && r <= R)
    {
        return sum[rt];
    }

    int m = (l + r) >> 1;
    int ret = 0;

    //下面采用分治法(从中间劈开是为了逐渐减小问题规模)
    //注:L<=m表示查询的范围在左儿子中“有”;R>m表示查询的范围在右儿子中“有”!
    if (L <= m) ret += query(L, R, lson);   //#define lson l m rt<<1
    if (R > m) ret += query(L, R, rson);     //#define rson m+1 r rt<<1|1
    return ret;
}


int main()
{
    int T, n; //T组数据,N个营地
    scanf("%d",&T);
    for (int cas = 1 ; cas <= T ; cas ++)
    {
        printf("Case %d:\n",cas);
        scanf("%d",&n);
        build(1, n, 1);
        //注意:根节点编号为1,然后从左到右、从上到下编号。这样,左儿子编号=rt<<1, 右儿子编号=rt<<1|1;
        //build(1,n,1)的结果将是:以标号1(param3)为根的子树的叶节点分别对应sum[1],sum[2],sum[3],...sum[n](n=10);
        //且构建的这棵树的每个内部节点i的sum[i]均为它所在子树的所有叶节点∑sum[j](j为叶节点编号)

        char op[10];
        while (scanf("%s",op))
        {
            if (op[0] == 'E') break;

            int a, b;
            scanf("%d%d",&a,&b);
            if (op[0] == 'Q') printf("%d\n",query(a, b, 1, n, 1));      //查询区间[a,b],总区间[1,n],树根1
            else if (op[0] == 'S') update(a, -b, 1, n, 1);      //单点a, 增量-b, 总区间[1,n],树根1
            else update(a, b, 1, n, 1);                         //单点a, 增量 b, 总区间[1,n],树根1
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/shengwang/p/9771476.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值