GSS4 - Can you answer these queries IV(线段树懒操作)
标签: 线段树
题目链接
Description
recursion有一个正整数序列a[n]。现在recursion有m次操作:
(A)对于给定的x,y,使所有满足下标i在x,y之间的数a[i]开方下取整。
(B)对于给定的x,y,输出满足下标i在x,y之间的数a[i]的和。
这么简单的题,recursion当然会做啦,但是为了维持她的傲娇属性,她决定考考你。
Input
包含多组数据,文件以EOF结尾。对于每组数据,第一行包含一个正整数n。第二行包含n个正整数,表示a[n]序列。第三行包含一个正整数m。接下来m行,每行包含三个整数i,x,y。i=0表示修改操作,i=1表示询问操作。
Output
对于每组数据,你需要先输出一个"Case #:",然后接下来每行输出一个询问的答案,最后留一个空行。具体见样例。
Sample Input
5
1 2 3 4 5
5
1 2 4
0 2 4
1 2 4
0 4 5
1 1 5
4
10 10 10 10
3
1 1 4
0 2 3
1 1 4
Sample Output
Case #1:
9
4
6
Case #2:
40
26
Hint
n,m<=100000,保证整个序列的和不超过1018
题意:
中文题意就不说了,但是要注意开根号的特点,一般像开根号,求连续数值的gcd这些都是下降非常快的函数,所以可以通过剪枝来优化复杂度,即满足一定条件就不算了
题解:
这个题就是一个普通的线段树加上一个懒操作,即如果当前的区间和正好等于当前的区间长度的话就不再更新这个节点
注意:
这个题要注意查询区间的正确性,l<r
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
#define mid (l+r>>1)
#define lc (d<<1)
#define rc (d<<1|1)
const int N = 100004;
ll sum[N<<2];
//int idl[N],idr[N];
//ll mp[N];
//int c;
void build(int l, int r, int d)
{
if(l==r)
{
scanf("%lld",&sum[d]);
// printf("%d ",sum[d]);
// idl[d] = idr[d] = c-1;
return;
}
build(l,mid,lc);
build(mid+1,r,rc);
sum[d] = sum[lc]+sum[rc];
// idl[d] = idl[lc];
// idr[d] = idr[rc];
//printf("%d %d %d
",d,idl[d],idr[d]);
return;
}
void Update(int L, int R, int l, int r, int d)
{
if(sum[d] == r-l+1) return;
if(l==r){
sum[d] = sqrt((double)sum[d]);
//mp[l] = sum[d];
return;
}
if(R <= mid) Update(L,R,l,mid,lc);
else if(L > mid) Update(L,R,mid+1,r,rc);
else {
Update(L,mid,l,mid,lc);
Update(mid+1,R,mid+1,r,rc);
}
sum[d] = sum[lc]+sum[rc];
return;
/*
if(L <= l && R >= r)
{
if(L==R)
{
sum[d] = pow((double)mp[idl[d]],0.5);
return;
}
for(int i = idl[d]; i <= idr[d]; i++)
{
sum[d] = sum[d]+pow((double)mp[i],0.5)-mp[i];
}
Update(L,R,l,mid,lc);
Update(L,R,mid+1,r,rc);
}
if(L <= mid) Update(L,R,l,mid,lc);
if(R > mid) Update(L,R,mid+1,r,rc);
return;
*/
}
ll query(int L, int R, int l, int r, int d)
{
if(L==l&&R==r)
{
return sum[d];
}
else if(R<=mid) return query(L,R,l,mid,lc);
else if(L>mid) return query(L,R,mid+1,r,rc);
ll t1 = query(L,mid,l,mid,lc);
ll t2 = query(mid+1,R,mid+1,r,rc);
return t1+t2;
}
int main()
{
int n,m,cnt;
cnt = 0;
int id, x, y;
while(~scanf("%d",&n))
{
cnt++;
//memset(sum,0,sizeof(sum));
//for(int i = 1; i <= n; i++)
// {
// scanf("%lld",&mp[i]);
// }
//c = 1;
build(1,n,1);
scanf("%d",&m);
printf("Case #%d:
",cnt);
//for(int i = 1; i <= m; i++)
while(m--)
{
scanf("%d%d%d",&id,&x,&y);
if(x>y) swap(x,y);//这句话很重要。。。不加就超时了
if(id==0)
{
Update(x,y,1,n,1);
}
else if(id==1)
{
ll ans = query(x,y,1,n,1);
printf("%lld
",ans);
}
}
}
return 0;
}