花神游历各国 (BZOJ-3211)
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4
Sample Output
101 11 11
Hint
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
思路:
题意很好理解,就是给了一段区间,有两种操作,一种是求区间的和,另一种是给一个区间开根号。
首先,给一个数开根号是很费时间的,那么我们也知道一个数开根号,在有限的次数内,会很快的到达1,既然已经变成1了,那么就不用开根号了,所以我们额外用一个flag数组来记录一个节点有没有到达1这个状态.来节省开根号的时间,所以对于0和1用flag标记一下就可以了。
这样当一段区间是1的时候,就不用去更新了,会节省时间。
不能判断区间和是否==r-l+1因为会出现0。
AC代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
#include <algorithm>
#include <stdlib.h>
#include <queue>
#include <stack>
#include <map>
#include <vector>
#define PI 3.1415926
#define inf 0x3f3f3f3f
const int maxn=100010;
using namespace std;
long long Sum[maxn<<2];
long long A[maxn<<2];
void PushUp(long long rt)
{
Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];
A[rt]=A[rt<<1]&&A[rt<<1|1];
}
void Build(long long l,long long r,long long rt)
{
if(l==r)
{
scanf("%d",&Sum[rt]);
if(Sum[rt]<=1)
A[rt]=1;
return;
}
long long m=(l+r)>>1;
Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
PushUp(rt);
}
void Update(int x,int y,int l,int r,int rt)
{
if(A[rt]==1)
return;
if(l==r)
{
Sum[rt]=floor(sqrt(Sum[rt]));
if(Sum[rt]<=1)
A[rt]=1;
return;
}
int m=(l+r)>>1;
if(x<=m)
Update(x,y,l,m,rt<<1);
if(y>m)
Update(x,y,m+1,r,rt<<1|1);
PushUp(rt);
}
long long Query(long long x,long long y,long long l,long long r,long long rt)
{
if(x<=l && r<=y)
return Sum[rt];
long long m=(l+r)>>1;
long long num=0;
if(x<=m)
num+=Query(x,y,l,m,rt<<1);
if(y>m)
num+=Query(x,y,m+1,r,rt<<1|1);
return num;
}
int main()
{
long long n,m;
while(~scanf("%lld",&n))
{
Build(1,n,1);
scanf("%lld",&m);
long long a,b,c;
while(m--)
{
scanf("%lld%lld%lld",&a,&b,&c);
if(a==1)
printf("%lld\n",Query(b,c,1,n,1));
else if(a==2)
Update(b,c,1,n,1);
}
}
return 0;
}