hdu 4027 Can you answer these queries?

题意:将题目的背景去掉,简单的说,就是每一次对一个区间的所有值都分别做一次求平方根的运算,就是将那个值改为它的平方根的值,每次再询问一段区间内的总和

分析:很明显的用线段树来做,不过明显的对线段树还是不熟悉,一开始将每一步update操作都更新到具体的每一个点了,没有任何技巧,直接TLE;很明显,如果每一步都必须更新的具体每一个点的话,就是一个

O(n)复杂度的操作了,这个对使用线段树来说,没太大意义了。

这题目而言,我们发现,任何一个2^63次方以内的数,开根号都至多开八次,也就是,多次询问操作之后,很多都已经不需要update了,所以,只需要在每一个节点中增加一个域,用来标记该区间是否已经全部更新到0或者1了,若满足条件,则不需要更新了

 

#include<iostream>
#include<math.h>
#define MAXN 100002
using namespace std;
__int64 c[MAXN];
struct node
{
	int l,r;
	__int64 sum;
	bool d;
}p[MAXN*4];
void bulid(int s,int t,int k)
{
	p[k].l=s;p[k].r=t;
	if(t==s)
	{
		p[k].sum=c[s];
		p[k].d=(c[s]<=1LL);
		return ;
	}
	int kl=k<<1,kr=kl+1,mid=(s+t)>>1;
	bulid(s,mid,kl);
	bulid(mid+1,t,kr);
	p[k].sum=p[kl].sum+p[kr].sum;
	p[k].d=p[kl].d && p[kr].d;
}
void decr(int k,int l,int r)
{
	if(p[k].l>r||p[k].r<l) return ;
	if(p[k].d) return;
	if(p[k].r==p[k].l)
	{
		p[k].sum=(__int64)(sqrt((double)p[k].sum));
		p[k].d=(p[k].sum<=1LL);
		return ;
	}
	int kl=k<<1,kr=kl+1;
	decr(kl,l,r);
	decr(kr,l,r);
    p[k].sum=p[kr].sum+p[kl].sum;
	p[k].d=p[kr].d && p[kl].d;
}
__int64 query(int k,int l,int r)
{
	if(p[k].l>r||p[k].r<l) return 0;
	if(p[k].l>=l&&p[k].r<=r) 
		return p[k].sum;
	int kl=k<<1,kr=kl+1;
	return query(kl,l,r)+query(kr,l,r);
}
int main()
{
	int n,m,a,b,cas=0,k;
	while(scanf("%d",&n)==1)
	{
		for(int i=1;i<=n;i++)
			scanf("%I64d",&c[i]);
		bulid(1,n,1);
		printf("Case #%d:\n",++cas);
		scanf("%d",&m);
		while(m--)
		{
			scanf("%d %d %d",&k,&a,&b);
			if(a>b) {int temp=a;a=b;b=temp;}
			if(k==0)
				decr(1,a,b);
			else printf("%I64d\n",query(1,a,b));
		}
		printf("\n");
	}
	return 0;
}
posted @ 2011-09-14 20:49  枕边梦  阅读(275)  评论(0编辑  收藏  举报