zoukankan      html  css  js  c++  java
  • Bzoj3211花神游历各国

    提供一种数据结构,支持区间求和,以及区间开根号。

    这种题一般暴力谁都能打,主要是练线段树。

    下面给出两种解法:

    第一种,额外维护区间最大值。

    由于1、0开根是其本身,开根没有意义,我们维护区间最大值,如果区间最大值已经为1或0则直接return,否则继续向下开根。

    剩下的维护区间和就可以了。

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define ll long long 
    using namespace std;
    struct Sengment_Tree{
        int l,r;
        ll sum,maxn;
    }t[400200];
    int n,m;
    ll read(){
        ll sum=0;int f=1;char x=getchar();
        while(x<'0'||x>'9'){
            if(x=='-') f=-1;
            x=getchar();
        }while(x>='0'&&x<='9'){
            sum=sum*10+x-'0';
            x=getchar();
        }return sum*f;
    }
    void updata(int p){
        t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
        t[p].maxn=max(t[p<<1].maxn,t[p<<1|1].maxn);
    }
    void build(int p,int l,int r){
        t[p].l=l;t[p].r=r;
        if(l==r){
            t[p].sum=t[p].maxn=read();
            return;
        }
        int mid=l+r>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        updata(p);
    }
    void change(int p,int l,int r){
        if(t[p].maxn<=1) return ;
        if(t[p].l==t[p].r){
            t[p].sum=t[p].maxn=(ll)sqrt(t[p].sum);
            return ;
        }
        int mid=t[p].l+t[p].r>>1;
        if(l<=mid) change(p<<1,l,r);
        if(r>mid) change(p<<1|1,l,r);
        updata(p);
    }
    ll ask(int p,int l,int r){
        if(l<=t[p].l&&t[p].r<=r) return t[p].sum;
        int mid=t[p].l+t[p].r>>1;
        ll ans=0;
        if(l<=mid) ans+=ask(p<<1,l,r);
        if(r>mid) ans+=ask(p<<1|1,l,r);
        return ans;
    }
    int main(){
        int x,y,z;
        n=read();
        build(1,1,n);
        m=read();
        for(int i=1;i<=m;i++){
            x=read();y=read();z=read();
            if(x==1) printf("%lld
    ",ask(1,y,z));
            else change(1,y,z);
        }return 0;
    }
    View Code

    第二种,维护lazy,表示是否已经全是1或0。

    如果是,则直接return,否则继续向下开根。

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    #define ll long long 
    using namespace std;
    struct Sengment_Tree{
        int l,r,flag;
        ll sum;
    }t[400200];
    ll read(){
        ll sum=0;int f=1;char x=getchar();
        while(x<'0'||x>'9'){
            if(x=='-') f=-1;
            x=getchar();
        }while(x>='0'&&x<='9'){
            sum=sum*10+x-'0';
            x=getchar();
        }return sum*f;
    }
    int n,qnum;
    ll a[100050];
    void updata(int p){
        t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
        t[p].flag=t[p<<1].flag&t[p<<1|1].flag;
    }
    void build(int p,int l,int r){
        t[p].l=l;t[p].r=r;
        if(l==r){
            t[p].sum=a[l];
            if(a[l]==0||a[l]==1)
                t[p].flag=1;
            else t[p].flag=0;
            return ;
        }
        int mid=l+r>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        updata(p);
    }
    void change(int p,int l,int r){
        if(t[p].l==t[p].r){
            t[p].sum=(ll)sqrt(t[p].sum);
            if(t[p].sum==0||t[p].sum==1)
                t[p].flag=1;
            return ;
        }
        int mid=t[p].l+t[p].r>>1;
        if(l<=mid&&!t[p<<1].flag) change(p<<1,l,r);
        if(r>mid&&!t[p<<1|1].flag) change(p<<1|1,l,r);
        updata(p);
    }
    ll ask(int p,int l,int r){
    //    cout<<t[p].sum<<endl;
        if(l<=t[p].l&&t[p].r<=r) return t[p].sum;
        int mid=t[p].l+t[p].r>>1;
        ll ans=0;
        if(l<=mid) ans+=ask(p<<1,l,r);
        if(r>mid) ans+=ask(p<<1|1,l,r);
        return ans;
    }
    int main(){
    //    freopen("out.docx","w",stdout);
        int x,y,opt;
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        build(1,1,n);
        qnum=read();
        for(int i=1;i<=qnum;i++){
            opt=read();x=read();y=read();
            if(opt==1) printf("%lld
    ",ask(1,x,y));
            else change(1,x,y);
        }return 0;
    } 
    View Code

    时间复杂度上来说,每个数最多被开大约5次(可以自己拿计算机按按),那么每个区间最多拜访的次数也不会太大,所以均摊一下,过掉这道题是没什么问题的。

  • 相关阅读:
    比率(ratio)|帕雷托图|雷达图|轮廓图|条形图|茎叶图|直方图|线图|折线图|间隔数据|比例数据|标准分数|标准差系数|离散系数|平均差|异众比率|四分位差|切比雪夫|右偏分布|
    质量控制|样本和总体|有限总体和无限总体|样本空间与变量空间|总体变异性|
    基因共线性
    q检验|新复极差法|LSD|二因素方差分析
    Tript协议|伯尔尼公约|著作权|立法宗旨|自动保护|著作权集体管理|
    两块式开头样板
    三块式开头样板
    listening-conversation|信息简写|Generally|回答|矛盾
    Listening-lecture|主旨题|术语解释|举例原则|Crash course 哔哩哔哩
    Do jobs|permanent|secure job|Move|Look after|provide sb with sth|Move|Enjoy a good time|Learn about|Be fond of|Have a clearer idea|String quarter|Be subject to|A has little with B|Pigment
  • 原文地址:https://www.cnblogs.com/Yu-shi/p/11138129.html
Copyright © 2011-2022 走看看