您的位置:首页 > 产品设计 > UI/UE

HDU 4027 Can you answer these queries?(线段树)

2016-01-05 14:00 381 查看
Description

给出n个数,m次操作,操作有两种:

1.0 a b:将区间[a,b]中的所有数都开更号(向下取整)

2.1 a b:查询区间[a,b]中元素之和

Input

第一行为一整数n表示序列长度,第二行n个整数ai表示这个序列,第三行为一整数m表示操作数,之后m行每行三个整数表示一次操作

(1<=n,m<=100000,0< ai<=2^63)

Output

对于每次询问,输出查询结果

Sample Input

10

1 2 3 4 5 6 7 8 9 10

5

0 1 10

1 1 10

1 1 5

0 5 8

1 4 8

Sample Output

Case #1:

19

7

6

Solution

一个不大于2^63的整数至多经过6次开更号就会变成1,所以就算所有点都更新复杂度也不会超过O(6*n),因此在用线段树维护区间和的时候,如果一个区间的和已经等于这个区间的长度,那么就不用往下继续更新了,因为这时候区间所有元素都已经是1了

Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
#define maxn 111111
struct Tree
{
int left,right;
ll sum;
}T[4*maxn];
void push_up(int t)
{
T[t].sum=T[2*t].sum+T[2*t+1].sum;
}
void build(int l,int r,int t)
{
T[t].left=l;
T[t].right=r;
if(l==r)
{
scanf("%lld",&T[t].sum);
return ;
}
int mid=(l+r)>>1;
build(l,mid,2*t);
build(mid+1,r,2*t+1);
push_up(t);
}
void update(int l,int r,int t)
{
if(T[t].left==T[t].right)
{
T[t].sum=sqrt(1.0*T[t].sum);
return ;
}
if(T[t].left==l&&T[t].right==r&&T[t].sum==r-l+1)return ;
int mid=(T[t].left+T[t].right)>>1;
if(r<=mid)update(l,r,2*t);
else if(l>mid)update(l,r,2*t+1);
else
{
update(l,mid,2*t);
update(mid+1,r,2*t+1);
}
push_up(t);
}
ll query(int l,int r,int t)
{
if(T[t].left==l&&T[t].right==r)return T[t].sum;
int mid=(T[t].left+T[t].right)>>1;
if(r<=mid)return query(l,r,2*t);
if(l>mid)return query(l,r,2*t+1);
return query(l,mid,2*t)+query(mid+1,r,2*t+1);
}
int main()
{
int n,m,res=1;
while(~scanf("%d",&n))
{
build(1,n,1);
scanf("%d",&m);
printf("Case #%d:\n",res++);
while(m--)
{
int op,a,b;
scanf("%d%d%d",&op,&a,&b);
if(a>b)swap(a,b);
if(op==0)
update(a,b,1);
else
printf("%lld\n",query(a,b,1));
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: