1. 程式人生 > >hdu 4027 Can you answer these queries?(線段樹)(單點更新 但需要標記記錄剪枝)

hdu 4027 Can you answer these queries?(線段樹)(單點更新 但需要標記記錄剪枝)

題目:http://acm.hdu.edu.cn/showproblem.php?pid=4027

題目大意:給定100000個數,兩種操作,0 i j表示將i j這段的數字都開根號(向下取整),1 i j表示查詢i j之間的所有值的和。。。(所有的和都不超過64位)..(用long long)

思路:因為是開根號,所以是要查詢到葉節點對葉節點進行開根號處理

這裡需要用到開個陣列記錄,如果葉節點小於等於1時再開根號值就不會發生變化,則將此位置標記為1,則下次要到這個位置時再不要在往下更新

#include<iostream>
#include<cmath>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<stdlib.h>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int  maxn =110000;
long long sum[maxn<<2];
long long col[maxn<<2];
void pushup(int rt)//將當前結點的資訊更新的父節點
{
	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
	col[rt]=col[rt<<1]&&col[rt<<1|1];
}
void build(int l,int r,int rt)//建立線段樹
{
	if(l==r)
	{
		scanf("%lld",&sum[rt]);
		return ;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
	pushup(rt);
}

long long  query(int L,int R,int l,int r,int rt)
{
	if(l>=L&&r<=R)
		return sum[rt];
	int m=(l+r)>>1;
	long long  ret=0;
	if(L<=m)ret+=query(L,R,lson);
	if(R>m)ret+=query(L,R,rson);
	pushup(rt);
	return ret;
}
void update(int L,int R,int l,int r,int rt)
{

	if(l==r)
	{
		sum[rt]=(int)sqrt((double)sum[rt]);
		if(sum[rt]<=1) col[rt]=1;//如果小於等於1時  開根號值不變 不需要在進行開根號操作
		return ;
	}
	int m=(l+r)>>1;
	if (L<=m&&!col[rt<<1])update(L,R,lson);//判斷是否需要往下更新
	if (R>m&&!col[rt<<1|1])update(L,R,rson);
	pushup(rt);//子節點更新完之後也要對其父節點不斷往上的更新
}
int main()
{
	int n,m;
	int t=1;
	while(~scanf("%d",&n))
	{
		memset(col,0,sizeof col);
		memset(sum,0,sizeof sum);
		build(1,n,1);

		scanf("%d",&m);
		int a;
		long long b,c;
		printf("Case #%d:\n",t++);
		for(int i=0;i<m;i++)
		{
			scanf("%d%lld%lld",&a,&b,&c);
			if(b>c)swap(b,c);
			if(a==0)
			{
				update(b,c,1,n,1);
			}
			else
			{
				printf("%lld\n",query(b,c,1,n,1));
			}
		}
		printf("\n");
	}
}