HDU 1166 敌兵布阵

本文通过一个具体的编程题目介绍了树状数组和线段树两种数据结构的应用。不仅提供了树状数组实现的代码,还详细展示了线段树的模板代码,包括建树、点修改、区间修改和查询等核心功能。

敌兵布阵

题目链接:点击打开链接


题目和本博客里之前的题目没什么区别,都是典型的树状数组增删改查。


代码如下:

#include<stdio.h>
#include<string.h>
#define MAXN 50005
int tree[MAXN];
int data[MAXN];
void add(int x,int num)
{
	for(int i=x;i<MAXN;i+=i&(-i))
		tree[i]+=num;
}
int read(int x)
{
	int sum=0;
	for(int i=x;i>0;i-=i&(-i))
		sum+=tree[i];
	return sum;
}
void A()
{
	int x,num;
	scanf("%d%d",&x,&num);
	x++;
	add(x,num);
}
void S()
{
	int x,num;
	scanf("%d%d",&x,&num);
	x++;
	add(x,-num);
}
void Q()
{
	int x,y;
	scanf("%d%d",&x,&y);
	x++;y++;
	int sum=read(y)-read(x-1);
	printf("%d\n",sum);
}
int main()
{
	int t,n;
	int index=1;
	char str[10];
	scanf("%d",&t);
	while(t--)
	{
		memset(tree,0,sizeof(tree));
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&data[i]);
			add(i+2,data[i]);
		}
		printf("Case %d:\n",index++);
		while(scanf("%s",&str))
		{
			if(str[0]=='A')
				A();
			else if(str[0]=='S')
				S();
			else if(str[0]=='Q')
				Q();
			else if(str[0]=='E')
				break;
		}
	}
	return 0;
}

2017/9/27 加入线段树模板代码:

#include<iostream>
#include<cstdio>
using namespace std;
//(0)定义
#define maxn 100007 //元素的总个数
#define ls,l,m,rt<<1
#define rs m+1,r,rt<<1|1

void PushDown(int rt,int ln,int rn);//声明
void Update(int L,int C,int l,int r,int rt);
int Sum[maxn<<2],Add[maxn<<2];  //Sum构成线段树,Add为懒惰数组
int n,A[maxn];  //原数组下标[1,n];
//(1)建树
void PushUp(int rt) {Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];}
void Build(int l,int r,int rt)//l,r表示当前结点区间,rt当前节点编号
{
    if(l==r){
        Sum[rt]=A[l];
        return ;
    }
    int m=(l+r)>>1;
    Build(l,m,rt<<1);
    Build(m+1,r,rt<<1|1);
    PushUp(rt);
}
//(2)点修改
void Update(int L,int C,int l,int r,int rt)//l,r表示当前节点区间,rt表示当前节点编号
{
    if(l==r){
        Sum[rt]+=C;
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m)    Update(L,C,l,m,rt<<1);
    else        Update(L,C,m+1,r,rt<<1|1);
    PushUp(rt);
}
void Update(int L,int R,int C,int l,int r,int rt)
{
    if(L<=l && r<=R){
        Sum[rt]+=C*(r-l+1);
        Add[rt]+=C;
        return ;
    }
    int m=(l+r)>>1;
    PushDown(rt,m-l+1,r-m);
    if(L<=m) Update(L,R,C,l,m,rt<<1);
    if(R>m) Update(L,R,C,m+1,r,rt<<1|1);
    PushUp(rt);
}
void PushDown(int rt,int ln,int rn)
{//ln,rn为左子树,右子树的数字数量。
    if(Add[rt])
    {//下推标记
        Add[rt<<1]+=Add[rt];
        Add[rt<<1|1]=Add[rt];
        Sum[rt<<1]+=Add[rt]*ln;
        Sum[rt<<1|1]+=Add[rt]*rn;
        Add[rt]=0;  //清除标记
    }
}
int Query(int L,int R,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
    if(L <= l && r <= R){
        //在区间内,直接返回
        return Sum[rt];
    }
    int m=(l+r)>>1;
    //下推标记,否则Sum可能不正确
    PushDown(rt,m-l+1,r-m);
    //累计答案
    int ANS=0;
    if(L <= m) ANS+=Query(L,R,l,m,rt<<1);
    if(R >  m) ANS+=Query(L,R,m+1,r,rt<<1|1);
    return ANS;
}

int main()
{
    int L,R,C,n,t;
    char str[15];
    int l,r,inde;
    inde=0;
    scanf("%d",&t);
    while(t--)
    {
        printf("Case %d:\n",++inde);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&A[i]);
        Build(1,n,1);//建树
        while(1)
        {
            scanf("%s",&str);
            if(str[0]=='E')
                break;
            else{
                scanf("%d%d",&l,&r);
                if(str[0]=='A')
                    Update(l,r,1,n,1);//点修改
                else if(str[0]=='S')
                    Update(l,-r,1,n,1);//点修改
                else{
                    int ANS=Query(l,r,1,n,1);//区间查询
                    printf("%d\n",ANS);
                }
            }
        }
    }
//      Build(1,n,1);//建树
//    Update(L,C,1,n,1);//点修改
//    Update(L,R,C,1,n,1);//区间修改
//    int ANS=Query(L,R,1,n,1);//区间查询

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值