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

来源:互联网 发布:淘宝网店推广论文 编辑:程序博客网 时间:2024/05/16 19:57

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 111111struct 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;}
0 0