去年上海赛区网络赛的一道简单题,数据量很大,不过要捉住题目中的重点,就是每次更新是对这个区间的所有的数开平方,从2^64开平方一直开尽(由于是开方取整),所以开6次即可。即使是一个个点更新,复杂度也只不过是O(6N)。用COL[]纪录线段中的数据是不是被开尽,这样就节省了后面的无用功。另外注意的是x,y会颠倒。。因为题目中说的是between x and y显然没有交代大小关系。。附代码:
#include <iostream>
#include <cmath>
using namespace std;
#define clear(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N=100100;
__int64 sum[N<<2],col[N<<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("%I64d",&sum[rt]);
return;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
__int64 query(int L,int R,int l,int r,int rt)
{
if (L<=l&&r<=R)
{
return sum[rt];
}
int m=(l+r)>>1;
__int64 ret=0;
if (L<=m) ret+=query(L,R,lson);
if (R>m) ret+=query(L,R,rson);
return ret;
}
void update(int L,int R,int l,int r,int rt)
{
if (l==r)
{
sum[rt]=sqrt(sum[rt]);
if (sum[rt]<=1) col[rt]=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 i,n,m,k=0;
while (scanf("%d",&n)!=EOF)
{
k++;
clear(sum);
clear(col);
build(1,n,1);
scanf("%d",&m);
printf("Case #%d:\n",k);
int z,x,y;
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&z,&x,&y);
if (x>y)
{
int tmp=x;
x=y;
y=tmp;
}
if (z==1)
{
__int64 s=query(x,y,1,n,1);
printf("%I64d\n",s);
}
else update(x,y,1,n,1);
}
printf("\n");
}
return 0;
}