T - Can you answer these queries?(单点更新,线段树优化)

http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=216#problem/T


对n个整数有m个操作,共有两种操作:0 l r表示把区间[l,r]之间的数开方,1 l r表示询问[l,r]的和。


开方即单点更新。但所有的数都单点更新和模拟每什么差别。重点就是成段维护区间的和,因为当操作次数相当多时,这些数大部分就会变成1,因此可以用线段树维护区间的和,当这个区间的数全部是1就没必要更新了。


#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
//#define LL long long
#define LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 100010;

struct node
{
	int l,r;
	LL sum;
}tree[maxn*4];

LL a[maxn];

void build(int v, int l, int r)
{
	tree[v].l = l;
	tree[v].r = r;
	if(l == r)
	{
		tree[v].sum = a[l];
		return;
	}
	int mid = (l+r)>>1;
	build(v*2,l,mid);
	build(v*2+1,mid+1,r);
	tree[v].sum = tree[v*2].sum + tree[v*2+1].sum;
}

void update(int v, int l, int r)
{
	if(tree[v].sum == tree[v].r - tree[v].l + 1)
		return;
	if(tree[v].l == tree[v].r)
	{
		tree[v].sum = sqrt(tree[v].sum*1.0);
		return;
	}
	int mid = (tree[v].l + tree[v].r) >> 1;
	if(r <= mid)
		update(v*2,l,r);
	else if(l > mid)
		update(v*2+1,l,r);
	else
	{
		update(v*2,l,mid);
		update(v*2+1,mid+1,r);
	}
	tree[v].sum = tree[v*2].sum + tree[v*2+1].sum;
}

LL query(int v, int l, int r)
{
	if(tree[v].l == l && tree[v].r == r)
		return tree[v].sum;
	int mid = (tree[v].l + tree[v].r) >> 1;
	if(r <= mid)
		return query(v*2,l,r);
	else if(l > mid)
		return query(v*2+1,l,r);
	else
		return query(v*2,l,mid) + query(v*2+1,mid+1,r);
}

int main()
{
	int n,m,item = 1;
	int x,l,r;

	while(~scanf("%d",&n))
	{
		for(int i = 1; i <= n; i++)
			scanf("%I64d",&a[i]);
		build(1,1,n);
		scanf("%d",&m);
		printf("Case #%d:\n",item++);
		while(m--)
		{
			scanf("%d %d %d",&x,&l,&r);
			if(l > r)
				swap(l,r);
			if(x == 0)
				update(1,l,r);
			else
				printf("%I64d\n",query(1,l,r));
		}
		printf("\n");
	}
	return 0;
}


你可能感兴趣的:(线段树)