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;
}