Simple Data Structures 2019银川网络赛A题(线段树)

题目链接:Simple Data Structures

赛中写了一个复杂度教高的写法,在数据随机的情况下大概是一秒左右起伏,当时写了一个暴力对拍,拍了十分钟随机数据都可以过,结果比赛过程中我也不知道多会改的题面说不可以用lld要用I64d就很无语。。。

这个做法是参考18年wannfly-camp中提到过的区间与,区间或,区间最大值的写法,可以看一下我这篇:区间或,区间与,区间最大值

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;

typedef long long ll;

const int maxn=1e5+7;

ll sum[maxn<<2|1];
ll lazy[maxn<<2|1];
int is[maxn<<2|1][39];

int is01[maxn<<2|1][39];

void pushup(int k){
    sum[k]=sum[k<<1]+sum[k<<1|1];
    for(int i=0;i<=20;++i){
        if(is01[k<<1][i]==is01[k<<1|1][i]) is01[k][i]=is01[k<<1][i];
        else is01[k][i]=2;
    }
}

void pushup2(int k,int pos){
    sum[k]=sum[k<<1]+sum[k<<1|1];
    if(is01[k<<1][pos]==is01[k<<1|1][pos]) is01[k][pos]=is01[k<<1][pos];
    else is01[k][pos]=2;
}
void build(int l,int r,int k){
    lazy[k]=0;
    for(int i=0;i<=20;++i) is[k][i]=-1;
    if(l==r){
        scanf("%lld",&sum[k]);
        for(int i=0;i<=20;++i)
            if(sum[k]&(1<<i)) is01[k][i]=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    pushup(k);
}

void pushdown(int l,int r,int k){
    if(lazy[k]){
        int mid=(l+r)>>1;
        lazy[k<<1]+=lazy[k];
        lazy[k<<1|1]+=lazy[k];
        sum[k<<1]+=(mid-l+1)*lazy[k];
        sum[k<<1|1]+=(r-mid)*lazy[k];
        lazy[k]=0;
    }
    for(int i=0;i<=30;++i)
        if(is[k][i]!=-1){
            is[k<<1][i]=is[k][i];
            is[k<<1|1][i]=is[k][i];
            is01[k<<1][i]=is[k][i];
            is01[k<<1|1][i]=is[k][i];
            is[k][i]=-1;
        }
}

void pushdown2(int l,int r,int k,int id){
    if(lazy[k]){
        int mid=(l+r)>>1;
        lazy[k<<1]+=lazy[k];
        lazy[k<<1|1]+=lazy[k];
        sum[k<<1]+=(mid-l+1)*lazy[k];
        sum[k<<1|1]+=(r-mid)*lazy[k];
        lazy[k]=0;
    }
    if(is[k][id]!=-1){
        is[k<<1][id]=is[k][id];
        is[k<<1|1][id]=is[k][id];
        is01[k<<1][id]=is[k][id];
        is01[k<<1|1][id]=is[k][id];
        is[k][id]=-1;
    }
}

//1& 2| 3^ num 01
void updata(int l,int r,int k,int L,int R,int pos,int type,int num){
    if(l==r){
        if(type==1){
            if(is01[k][pos]&&num==0) sum[k]-=(1<<pos),is01[k][pos]=0;
        }
        else if(type==2){
            if(is01[k][pos]==0&&num) sum[k]+=(1<<pos),is01[k][pos]=1;
        }
        else{
            if(is01[k][pos]&&num) sum[k]-=(1<<pos),is01[k][pos]=0;
            else if(is01[k][pos]==0&&num) sum[k]+=(1<<pos),is01[k][pos]=1;
        }
        return ;
    }
    if(l>=L&&r<=R){
        if(type==1){
            if(is01[k][pos]==1&&num==0){
                sum[k]-=(r-l+1)*(1<<pos),is01[k][pos]=0;
                lazy[k]-=(1<<pos);
                is[k][pos]=0;
            }
        }
        else if(type==2){
            if(is01[k][pos]==0&&num){
                sum[k]+=(r-l+1)*(1<<pos),is01[k][pos]=1;
                lazy[k]+=(1<<pos);
                is[k][pos]=1;
            }
        }
        else{
            if(is01[k][pos]==1&&num){
                sum[k]-=(r-l+1)*(1<<pos),is01[k][pos]=0;
                lazy[k]-=(1<<pos);
                is[k][pos]=0;
            }
            else if(is01[k][pos]==0&&num){
                sum[k]+=(r-l+1)*(1<<pos),is01[k][pos]=1;
                lazy[k]+=(1<<pos);
                is[k][pos]=1;
            }
        }
        if(is01[k][pos]!=2) return ;
    }
    //pushdown(k,pos);
    pushdown2(l,r,k,pos);
    int mid=(l+r)>>1;
    if(L<=mid) updata(l,mid,k<<1,L,R,pos,type,num);
    if(R>mid) updata(mid+1,r,k<<1|1,L,R,pos,type,num);
    pushup2(k,pos);
}

ll myfind(int l,int r,int k,int L,int R){
    if(l>=L&&r<=R) return sum[k];
    pushdown(l,r,k);
    //for(int i=0;i<=30;++i) pushdown(k,i);
    int mid=(l+r)>>1;
    ll res=0;
    if(L<=mid) res+=myfind(l,mid,k<<1,L,R);
    if(R>mid) res+=myfind(mid+1,r,k<<1|1,L,R);
    pushup(k);
    return res;
}

int main(){
    int n,m;
    int id,l,r,x;
    scanf("%d",&n);
    build(1,n,1);
    scanf("%d",&m);
    while(m--){
        scanf("%d%d%d",&id,&l,&r);
        if(id==1) printf("%I64d\n",myfind(1,n,1,l,r));
        else if(id==4){//&;
            scanf("%d",&x);
            for(int i=0;i<=20;++i)
                if(x>>i&1) updata(1,n,1,l,r,i,1,1);
                else updata(1,n,1,l,r,i,1,0);
        }
        else if(id==3){//|;
            scanf("%d",&x);
            for(int i=0;i<=20;++i)
                if(x>>i&1) updata(1,n,1,l,r,i,2,1);
                else updata(1,n,1,l,r,i,2,0);
        }
        else{
            scanf("%d",&x);
            for(int i=0;i<=20;++i)
                if(x>>i&1) updata(1,n,1,l,r,i,3,1);
                else updata(1,n,1,l,r,i,3,0);
        }
    }

    return 0;
}

另一种较为优秀的是下传两种标记,一种是区间赋值,一种是区间翻转,&|运算相当于赋值,^相当于翻转。
要注意两种标记的时间顺序,如果赋值之前有翻转标记,那么翻转标记直接无效。
如果翻转之前有赋值操作,那么其实可以看作是赋相反的值(0赋1,1赋0),翻转标记无效化。
所以在标记下传的过程中,存在区间翻转就不会存在区间赋值,存在区间赋值就不会存在区间翻转。
(最后这句话没用。)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int sum[maxn<<2|1][29];
int revarse[maxn<<2|1][29];
int add[maxn<<2|1][29];


inline void pushup(int k,int pos){
    sum[k][pos]=sum[k<<1][pos]+sum[k<<1|1][pos];
}
void build(int l,int r,int k){
    for(int i=0;i<=24;++i) revarse[k][i]=0,add[k][i]=-1;
    int x;
    if(l==r){
        scanf("%d",&x);
        for(int i=0;i<=24;++i)
            if(x&(1<<i)) sum[k][i]=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    for(int i=0;i<=24;++i) pushup(k,i);
}

inline void pushdown(int l,int r,int k,int pos){
    int mid=(l+r)>>1;
    if(revarse[k][pos]){
        revarse[k<<1][pos]^=revarse[k][pos];
        revarse[k<<1|1][pos]^=revarse[k][pos];
        sum[k<<1][pos]=mid-l+1-sum[k<<1][pos];
        sum[k<<1|1][pos]=r-mid-sum[k<<1|1][pos];
        if(add[k<<1][pos]!=-1){
            add[k<<1][pos]^=1;
            revarse[k<<1][pos]=0;
        }
        if(add[k<<1|1][pos]!=-1){
            add[k<<1|1][pos]^=1;
            revarse[k<<1|1][pos]=0;
        }

        revarse[k][pos]=0;
    }
    if(add[k][pos]!=-1){
        add[k<<1][pos]=add[k<<1|1][pos]=add[k][pos];
        sum[k<<1][pos]=(mid-l+1)*add[k][pos];
        sum[k<<1|1][pos]=(r-mid)*add[k][pos];
        revarse[k<<1][pos]=revarse[k<<1|1][pos]=0;
        add[k][pos]=-1;
    }
}
//0 0 1 1 2 revarse;
void updata(int l,int r,int k,int L,int R,int type,int pos){
    if(l>=L&&r<=R){
        if(type==0){
            sum[k][pos]=0;
            add[k][pos]=0;
            revarse[k][pos]=0;
        }
        else if(type==1){
            sum[k][pos]=r-l+1;
            add[k][pos]=1;
            revarse[k][pos]=0;
        }
        else{
            revarse[k][pos]^=1;//如果之前有覆盖标记,那么就相当于覆盖为相反的数字,从而达到反转效果;
            sum[k][pos]=r-l+1-sum[k][pos];
            if(add[k][pos]!=-1){
                add[k][pos]^=1;
                revarse[k][pos]=0;
            }
        }
        return ;
    }
    pushdown(l,r,k,pos);
    int mid=(l+r)>>1;
    if(L<=mid) updata(l,mid,k<<1,L,R,type,pos);
    if(R>mid) updata(mid+1,r,k<<1|1,L,R,type,pos);
    pushup(k,pos);
}

int myfind(int l,int r,int k,int L,int R,int pos){
    if(l>=L&&r<=R) return sum[k][pos];
    int mid=(l+r)>>1;
    pushdown(l,r,k,pos);
    int res=0;
    if(L<=mid) res+=myfind(l,mid,k<<1,L,R,pos);
    if(R>mid) res+=myfind(mid+1,r,k<<1|1,L,R,pos);
    return res;
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out1.txt","w",stdout);
    int n,m,id,l,r,x;
    scanf("%d",&n);
    build(1,n,1);
    scanf("%d",&m);
    while(m--){
        scanf("%d%d%d",&id,&l,&r);
        if(id==1){
            ll res=0;
            for(int i=0;i<=24;++i) res+=(1LL<<i)*1LL*myfind(1,n,1,l,r,i);
            printf("%I64d\n",res);
        }
        else if(id==2){
            scanf("%d",&x);
            for(int i=0;i<=24;++i)
                if(x&(1<<i)) updata(1,n,1,l,r,2,i);
        }
        else if(id==3){
            scanf("%d",&x);
            for(int i=0;i<=24;++i)
                if(x&(1<<i)) updata(1,n,1,l,r,1,i);
        }
        else{
            scanf("%d",&x);
            for(int i=0;i<=24;++i)
                if(!(x&(1<<i))) updata(1,n,1,l,r,0,i);
        }
    }
    return 0;
}

热防护服是高温环境工作人群的重要保障,本文通过建立数学模型对多层热防护织物内部传热规律进行研究,建立防护服装内部的热传递模型,从而解决外界环境温度一定时,防护服各层随时间变化的温度分布问和各层织物材料的最优厚度问。 假人处于恒高温环境中,不考虑防护服织物的边缘热量损失,且人体和防护服的空气间隔很小,忽略空气的自然对流,只考虑热传导;故可以把织物视为导热多层平面,且属于非稳态导热过程。建立“高温环境-防护服-假人体表”系统;由傅里叶定律描述导热速率,将温度的变化转是能量传递的结果,将其看作电磁波的辐射和介质中对电磁波的传输问。 防护服中的温度分布由时间和防护服与外界热源相对位置二者共同决定的二元函数,因为二元偏微分方程的解析解无法精确求出,所以对时间进行离散化分析,分析以一秒为单位时间的温度变化与位置的关系,从而对问进行简化。 针对问一,将各层的导热过程抽象简化处理转换为平板中非稳态导热过程,在平板厚度的四周绝热良好时,从传热的角度上将问简化为一个一维传热问;从假人皮肤外侧的温度变化入手,根据热量的流向和生热情况从第Ⅳ层、第III层、第Ⅱ层、第Ⅰ层反向递推出和外界环境温度的关系,引入能温转换系数,建立假人皮肤外侧温度变化和外界温度的等式关系,最后利用最小二乘法设计程序,求出每一阶段的温度分布平差之后的结果,从而得到温度分布。 针对问二,考虑在一小时内该系统温度变化,用时间限制与温度阈值限制作为约束条件的规划问,沿用离散化分析手段,由假人体表温度逆推防护服第Ⅱ层厚度的表达式,建立其与外界温度的关系,并寻求满足条件下的最优解。 针对问三,考虑在给定半小时时间内该系统温度变化,添加更多的约束条件,对问二中的求解模型进行进一步优化,利用lingo寻找第Ⅱ、Ⅳ层厚度的最优解,并沿用前问中离散化分析手段,由假人体表温度逆推防护服相关设计参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值