HDU 1166 敌兵布阵

本文通过解决HDU1166敌兵布阵问题,介绍了如何使用段树(segment tree)进行区间更新和查询操作。文章分享了一个具体实现案例,包括构建段树、增加节点值以及查询区间和的方法。

今天本打算学VAL,结果为了把接口写得好看一些不得不和指针纠结——最后没写出来 :(

不过学习了SEGMENT TREE,还算是有收获。

我发现自己coding很差劲 :(

/*
 * HDU 1166 敌兵布阵
 * mike-w
 * 2011-8-14
 * ---------------------
 * hint:segment tree
 * PS:交上去发现78ms,不是很快,最快31ms
 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 300000
#define BUF_SIZE 50
#define L 0
#define R 1
#define SUM 2

long seg[MAXSIZE][3];

/*
 * build a segment tree
 * we assume x1<x2
 * r stands for root
 */
int build(long r,long x1,long x2)
{
	seg[r][L]=x1;
	seg[r][R]=x2;
	seg[r][SUM]=0;
	if(x1==x2)
		return 0;
	else if(x2-x1==1)
	{
		build(r<<1,x1,x1);
		build((r<<1)+1,x2,x2);
	}	
	else
	{
		long mid=(x1+x2)>>1;
		build(2*r,x1,mid);
		build(2*r+1,mid+1,x2);
	}
	return 0;
}

int add(long id,long n)
{
	long x1,x2,mid,r;

	r=1;
	x1=seg[r][L];
	x2=seg[r][R];
	mid=(x1+x2)>>1;

	while(x2!=x1)
	{
		seg[r][SUM]+=n;
		if(id<=mid)
			r<<=1;
		else
			r=(r<<1)+1;
	
		x1=seg[r][L];
		x2=seg[r][R];
		mid=(x1+x2)>>1;
	}
	seg[r][SUM]+=n;
	return 0;
}

/*
 * similiar to function build()
 * but they DIFFER
 */
long query(long r,long x1,long x2)
{
	long left=seg[r][L],
		 right=seg[r][R],
		 mid=(left+right)>>1;

	if(x1==left&&x2==right)
		return seg[r][SUM];
	else if(x2<=mid)
		return query(r<<1,x1,x2);
	else if(x1>mid)
		return query((r<<1)+1,x1,x2);
	else
		return query(r<<1,x1,mid)+query((r<<1)+1,mid+1,x2);
}

int main(void)
{
	int ncase,ccase=0;
	long N,i,j;
	char buf[BUF_SIZE];
	
#ifndef ONLINE_JUDGE
	freopen("1166.in","r",stdin);
#endif

	scanf("%d",&ncase);
	while(ncase--)
	{
		printf("Case %d:\n",++ccase);

		scanf("%ld",&N);
		build(1,1,N);
		for(i=1;i<=N;i++)
		{
			scanf("%ld",&j);
			add(i,j);
		}
		while(scanf("%s",buf),*buf!='E')
		{
			scanf("%ld%ld",&i,&j);
			if(*buf=='A')
				add(i,j);
			else if(*buf=='S')
				add(i,-j);
			else
				printf("%ld\n",query(1,i,j));
		}
	}
	return 0;
}


 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值