• 【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:
    ",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
    ",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:
    ",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
    ",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;
    }
    
  • 相关阅读:
    C#生成PDF总结
    Oracle删除当前用户下所有的表的方法
    C#操作oracle 到ExecuteNonQuery卡死不执行
    C#中事件的使用
    初探three.js光源
    d3.js 地铁轨道交通项目实战
    初探three.js
    d3.js 绘制北京市地铁线路状况图(部分)
    d3.js 共享交换平台demo
    d3.js 实现烟花鲜果
  • 原文地址:https://www.cnblogs.com/shengwang/p/9771476.html
Copyright © 2020-2023  润新知