zoukankan      html  css  js  c++  java
  • [bzoj3038/3211]上帝造题的七分钟2/花神游历各国_线段树

    上帝造题的七分钟2 bzoj-3038

    题目大意:给定一个序列,支持:区间开方;查询区间和。

    注释:$1le nle 10^5$,$1le val[i] le 10^{12}$。

    想法:这题还挺挺有意思的。查询区间和我们可以用前缀和,但是用上去区间修改就不难想到线段树。那么我们思考如何在log的时间之内完成区间开方。直接打lazy显然实现不了,其实我们发现,每一个$10^{12}$之内的数最多只需要开6次方就可以变成1,$10^{12}$开6次根号是1.53993。所以我们对每一个区间用一个mark标记表示这个区间是不是全是1。如果不是的话,我就暴力修改。这样的话每一个数最多会被修改6次,所以总时间复杂度是O(n*a),a是log级别的。

    P.S.:花神那道题卡读入,不加读入优化会T... ...

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #define N 100010 
    #define lson pos<<1
    #define rson pos<<1|1
    using namespace std;
    typedef long long ll;
    ll sum[N<<2],a[N];
    int n,m;
    inline void pushup(int pos)
    {
    	sum[pos]=sum[lson]+sum[rson];
    }
    void build(int pos,int l,int r)
    {
        if(l==r)
        {
            sum[pos]=a[l];
            return;
        }
        int mid=(l+r)>>1;
        build(lson,l,mid);
        build(rson,mid+1,r);
        pushup(pos);
    }
    void update(int pos,int l,int r,int x,int y)
    {
        if(x>y)swap(x,y);
        if(sum[pos]==r-l+1)return;
        if(l==r)
        {
            sum[pos]=(ll)sqrt(sum[pos]+0.5);
            return;
        }
        int mid=(l+r)>>1;
        if(y<=mid) update(lson,l,mid,x,y);
        else if(x>mid) update(rson,mid+1,r,x,y);
        else update(lson,l,mid,x,y),update(rson,mid+1,r,x,y);
        pushup(pos);
    }
    ll getsum(int pos,int l,int r,int x,int y)
    {
        if(x>y) swap(x,y);
        if(x<=l&&r<=y) return sum[pos];
        int mid=(l+r)>>1;
        if(y<=mid)return getsum(lson,l,mid,x,y);
        if(x>mid)return getsum(rson,mid+1,r,x,y);
        return getsum(lson,l,mid,x,y)+getsum(rson,mid+1,r,x,y);
    }
    void output()
    {
    	printf("Fuck : %lld
    ",sum[1]);
    }
    int main()
    {
        cin >> n ;
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        build(1,1,n);
        cin >> m ;
        for(int k,x,y,i=1;i<=m;i++)
        {
            scanf("%d%d%d",&k,&x,&y);
            if(!k) update(1,1,n,x,y);
            else printf("%lld
    ",getsum(1,1,n,x,y));
    		// output();
        }
        return 0;
    }
    

    小结:线段树是很神奇的...qwq

  • 相关阅读:
    .Net Core部署到CentOS
    Docker容器中开始.Net Core之路
    自我总结和学习表单提交的几种方式 (二)
    自我总结和学习表单提交的几种方式 (一)
    Asp.Net MVC下自定义错误页和展示错误页的几种方式
    .Net下发送邮件遇到问题及解决方案
    Asp.Net MVC CodeFirst模式数据库迁移步骤
    利用微软认知服务实现语音识别功能
    Asp.Net MVC路由生成URL过程
    针对于多线程概念的理解
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9291327.html
Copyright © 2011-2022 走看看