Can you answer these queries? HDU - 4027

原题链接
考察:线段树+剪枝
思路:
  参考大佬的思路.线段树也能剪枝是我没想到的.
  最大的数263最多开方6次就会变成1.考虑到这点可以考虑暴力.每次修改[l,r]实际转化为单点修改,但是要进行剪枝,如果当前区间的最大值已经 = 1,那么就没必要在往下搜.
  时间复杂度最坏是O(6*4*N+1e5*log2N)
  其中4*N是线段树所有点数,最多遍历6遍所有点.

Code

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
LL a[N];
int n,m;
struct Node{
	int l,r;
	LL maxn,sum;
}tr[N<<2];
void push_up(int u)
{
	tr[u].maxn = max(tr[u<<1].maxn,tr[u<<1|1].maxn);
	tr[u].sum = tr[u<<1].sum+tr[u<<1|1].sum;
}
void build(int u,int l,int r)
{
	tr[u].l = l,tr[u].r = r;
	if(l==r) {tr[u].maxn = tr[u].sum = a[l];return;}
	int mid = l+r>>1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
	push_up(u);
}
void modify(int u,int l,int r)
{
	if(tr[u].maxn==1) return;
	if(tr[u].l>=l&&tr[u].r<=r)
	{
		if(tr[u].l==tr[u].r)
		{
			tr[u].sum = sqrt(tr[u].sum*1.0);
			tr[u].maxn = tr[u].sum;
			return;
		}
	}
	int mid = tr[u].l+tr[u].r>>1;
	if(l<=mid) modify(u<<1,l,r);
	if(mid<r) modify(u<<1|1,l,r);
	push_up(u);
}
LL query(int u,int l,int r)
{
	if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;
	int mid = tr[u].l+tr[u].r>>1;
	LL res = 0;
	if(l<=mid) res+=query(u<<1,l,r);
	if(mid<r) res+=query(u<<1|1,l,r);
	return res;
}
int main()
{
	int kcase = 0;
	while(scanf("%d",&n)!=EOF)
	{
		printf("Case #%d:\n",++kcase);
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		scanf("%d",&m);
		build(1,1,n);
		while(m--)
		{
			int op,l,r; scanf("%d%d%d",&op,&l,&r);
			if(l>r) swap(l,r);
			if(op) printf("%lld\n",query(1,l,r));
			else modify(1,l,r);
		}
		printf("\n");
	}
	return 0;
}

posted @ 2021-05-20 16:06  acmloser  阅读(47)  评论(0编辑  收藏  举报