HDU - 4578 Transformation(线段树 - 区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578

题意:初始时给一个全为0的数列,有四种操作
(1)将x->y的数全部加上c;
(2)将x->y的数全部乘以c;
(3)将x->y的数全部赋值为c;
(4)查询x->y的每个数的p次方的和;

思路:这一题涉及到特别多的操作,但都是区间上的操作,所以可以想到线段树,但这一题我吗要打三个标记(lazy,lazyadd,lazymul,分别是区间替换,期间加和区间乘)再用三个数组(sum1,sum2,sum3分别表示1次方,2次方和3次方),还要用两个数组(L,R记录左右端点)之后,就是令人窒息的push_down函数的编写啦。
首先,我们有三个标记,所以我们要确定一个运算的优先级。毫无疑问,lazy标记一定是优先级最高的,其次,乘法的优先级高于加法。为什么呢?

假设我们现在有三个操作,
第一个是给x->y区间+3,
第二个是给区间x->y *4,
第三个是给区间x->y +5;
那总的式子应该是 ∑ \sum_{} (a+3)*4+5。
如果我们优先算加法的话,那我们算的应该是 ∑ \sum_{} (a+3+5/4)*4;
如果我们先算乘法的话,我们算的就是 ∑ \sum_{} a*4+3*4+5;
很明显,加法优先会涉及到分数运算,会丢失精度,
但乘法优先可以很完美的避开这一点。
这样的话,每次我们更新lazymul是也要把lazyadd更新一下。

明确了这个之后,还有一个就是2次方和三次方该怎么表示。
首先如果是赋值和乘法的话,那就是直接乘就好啦,主要是加法

∑ ( x + c ) ∗ ( x + c ) \sum_{}(x+c)*(x+c) (x+c)(x+c)= ∑ x ∗ x + 2 ∗ c ∗ x + c ∗ c \sum_{}x*x+2*c*x+c*c xx+2cx+cc
= ∑ x ∗ x \sum_{}x*x xx+ ∑ 2 ∗ c ∗ x \sum_{}2*c*x 2cx+ ∑ c ∗ c \sum_{}c*c cc
=sum2+2*c*sum1+c*c*(区间长度);

同理 ∑ ( x + c ) ∗ ( x + c ) ∗ ( x + c ) \sum_{}(x+c)*(x+c)*(x+c) (x+c)(x+c)(x+c)
= ∑ x ∗ x ∗ x \sum_{}x*x*x xxx+ ∑ 3 ∗ c ∗ x ∗ x \sum_{}3*c*x*x 3cxx+ ∑ 3 ∗ c ∗ c ∗ x \sum_{}3*c*c*x 3ccx+ ∑ c ∗ c ∗ c \sum_{}c*c*c ccc
=sum3+3*c*sum2+3*c*c*sum1+c*c*c*(区间长度)

想到这,这道题就差不多可以解决啦,不过这个代码真的不怎么好些们一定要细心,细心,再细心。

具体代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int maxn=1e5+7;
const LL mod=10007;

LL sum1[maxn<<2],sum2[maxn<<2],sum3[maxn<<2];
LL lazy[maxn<<2],lazyadd[maxn<<2],lazymul[maxn<<2];
LL L[maxn<<2],R[maxn<<2];

void push_up(int rt)
{
    sum1[rt]=(sum1[rt<<1]+sum1[rt<<1|1])%mod;
    sum2[rt]=(sum2[rt<<1]+sum2[rt<<1|1])%mod;
    sum3[rt]=(sum3[rt<<1]+sum3[rt<<1|1])%mod;
}

void build(int l,int r,int rt)
{
    lazy[rt]=lazyadd[rt]=0;
    lazymul[rt]=1;
    L[rt]=l,R[rt]=r;
    if(l==r)
    {
        sum1[rt]=sum2[rt]=sum3[rt]=0;
        return ;
    }
    int m=(l+r)>>1;
    build(lson),build(rson);
    push_up(rt);
}

void push_down(int rt)
{
    ///change
    if(lazy[rt])
    {
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        ///lazy不为0的话要把lazyadd和lazymul标记清空
        lazyadd[rt<<1]=lazyadd[rt<<1|1]=0;
        lazymul[rt<<1]=lazymul[rt<<1|1]=1;

        sum1[rt<<1]=(lazy[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
        sum2[rt<<1]=(lazy[rt]*lazy[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
        sum3[rt<<1]=(lazy[rt]*lazy[rt]*lazy[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;

        sum1[rt<<1|1]=(lazy[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
        sum2[rt<<1|1]=(lazy[rt]*lazy[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
        sum3[rt<<1|1]=(lazy[rt]*lazy[rt]*lazy[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
        
        ///更新完之后记得初始化
        lazy[rt]=0;
    }

    ///mul
    if(lazymul[rt]!=1)
    {
        lazymul[rt<<1]=(lazymul[rt<<1]*lazymul[rt])%mod;
        lazymul[rt<<1|1]=(lazymul[rt<<1|1]*lazymul[rt])%mod;
        
        ///更新lazymul标记时切记要把lazyadd标记也更新
        lazyadd[rt<<1]=(lazyadd[rt<<1]*lazymul[rt])%mod;
        lazyadd[rt<<1|1]=(lazyadd[rt<<1|1]*lazymul[rt])%mod;

        sum1[rt<<1]=(sum1[rt<<1]*lazymul[rt])%mod;
        sum2[rt<<1]=(sum2[rt<<1]*lazymul[rt]*lazymul[rt])%mod;
        sum3[rt<<1]=(sum3[rt<<1]*lazymul[rt]*lazymul[rt]*lazymul[rt])%mod;

        sum1[rt<<1|1]=(sum1[rt<<1|1]*lazymul[rt])%mod;
        sum2[rt<<1|1]=(sum2[rt<<1|1]*lazymul[rt]*lazymul[rt])%mod;
        sum3[rt<<1|1]=(sum3[rt<<1|1]*lazymul[rt]*lazymul[rt]*lazymul[rt])%mod;
        
        ///更新完之后记得初始化
        lazymul[rt]=1;
    }

    ///add
    if(lazyadd[rt])
    {
        lazyadd[rt<<1]=(lazyadd[rt<<1]+lazyadd[rt])%mod;
        lazyadd[rt<<1|1]=(lazyadd[rt<<1|1]+lazyadd[rt])%mod;
        
        ///根据推导的公式更新sum3,sum2和sum1
        sum3[rt<<1]=(sum3[rt<<1]+3LL*lazyadd[rt]*sum2[rt<<1]+3LL*lazyadd[rt]*lazyadd[rt]*sum1[rt<<1]+lazyadd[rt]*lazyadd[rt]*lazyadd[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
        sum2[rt<<1]=(sum2[rt<<1]+2LL*lazyadd[rt]*sum1[rt<<1]+lazyadd[rt]*lazyadd[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;
        sum1[rt<<1]=(sum1[rt<<1]+lazyadd[rt]*(R[rt<<1]-L[rt<<1]+1LL))%mod;

        sum3[rt<<1|1]=(sum3[rt<<1|1]+3LL*lazyadd[rt]*sum2[rt<<1|1]+3LL*lazyadd[rt]*lazyadd[rt]*sum1[rt<<1|1]+lazyadd[rt]*lazyadd[rt]*lazyadd[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
        sum2[rt<<1|1]=(sum2[rt<<1|1]+2LL*lazyadd[rt]*sum1[rt<<1|1]+lazyadd[rt]*lazyadd[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
        sum1[rt<<1|1]=(sum1[rt<<1|1]+lazyadd[rt]*(R[rt<<1|1]-L[rt<<1|1]+1LL))%mod;
        
        ///更新完之后记得初始化
        lazyadd[rt]=0;
    }

}

void update(int L1,int R1,LL val,int l,int r,int rt)
{
    if(L1<=l&&r<=R1)
    {
        lazy[rt]=val,lazymul[rt]=1,lazyadd[rt]=0;
        sum1[rt]=(val*(R[rt]-L[rt]+1LL))%mod;
        sum2[rt]=(val*val*(R[rt]-L[rt]+1LL))%mod;
        sum3[rt]=(val*val*val*(R[rt]-L[rt]+1LL))%mod;
        return ;
    }
    push_down(rt);
    int m=(l+r)>>1;
    if(L1<=m) update(L1,R1,val,lson);
    if(R1>m) update(L1,R1,val,rson);
    push_up(rt);
}

void updateadd(int L1,int R1,LL val,int l,int r,int rt)
{
    if(L1<=l&&r<=R1)
    {
        lazyadd[rt]=(lazyadd[rt]+val)%mod;
        sum3[rt]=(sum3[rt]+3LL*val*sum2[rt]+3LL*val*val*sum1[rt]+val*val*val*(R[rt]-L[rt]+1LL))%mod;
        sum2[rt]=(sum2[rt]+2LL*val*sum1[rt]+val*val*(R[rt]-L[rt]+1LL))%mod;
        sum1[rt]=(sum1[rt]+(R[rt]-L[rt]+1LL)*val)%mod;
        return ;
    }
    push_down(rt);
    int m=(l+r)>>1;
    if(L1<=m) updateadd(L1,R1,val,lson);
    if(R1>m) updateadd(L1,R1,val,rson);
    push_up(rt);
}

void updatemul(int L1,int R1,LL val,int l,int r,int rt)
{
    if(L1<=l&&r<=R1)
    {
        lazymul[rt]=(lazymul[rt]*val)%mod;
        lazyadd[rt]=(lazyadd[rt]*val)%mod;
        sum1[rt]=(sum1[rt]*val)%mod;
        sum2[rt]=(sum2[rt]*val*val)%mod;
        sum3[rt]=(sum3[rt]*val*val*val)%mod;
        return ;
    }
    push_down(rt);
    int m=(l+r)>>1;
    if(L1<=m) updatemul(L1,R1,val,lson);
    if(R1>m) updatemul(L1,R1,val,rson);
    push_up(rt);
}

LL query(int L1,int R1,int opt,int l,int r,int rt)
{
    if(L1<=l&&r<=R1)
    {
        if(opt==1) return sum1[rt];
        if(opt==2) return sum2[rt];
        if(opt==3) return sum3[rt];
    }
    push_down(rt);
    LL ans=0;
    int m=(l+r)>>1;
    if(L1<=m) ans=(ans+query(L1,R1,opt,lson))%mod;
    if(R1>m) ans=(ans+query(L1,R1,opt,rson))%mod;
    return ans%mod;
}

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)&&n&&m)
    {
        build(1,n,1);
        while(m--)
        {
            int opt,x,y;
            LL c;
            scanf("%d%d%d%lld",&opt,&x,&y,&c);
            if(opt==1) updateadd(x,y,c,1,n,1);
            else if(opt==2) updatemul(x,y,c,1,n,1);
            else if(opt==3) update(x,y,c,1,n,1);
            else printf("%lld\n",query(x,y,c,1,n,1));
        }
    }
    return 0;
}


极化码(Polar Code)是由土耳其科学家Erdal Arıkan在2009年提出的一种新型纠错编码技术。它通过利用信道的极化现象,将虚拟信道分为误码率接近0和接近1/2的两类。在编码设计中,数据被放置在误码率极低的信道上,从而实现高效的数据传输。极化码的主要优势在于其理论编码容量能够达到香农限,并且构造方法较为简单。 MATLAB是一种功能强大的数学计算和编程工具,广泛应用于科学研究和工程领域。在极化码的研究中,MATLAB可用于构建编码和解码算法,模拟数据在不同信道条件下的传输效果,验证理论性能,并优化相关参数。 SC(Successive Cancellation,逐位取消)译码是极化码的基本解码方法。它从最可靠的比特开始,依次解码每个虚拟信道,且每个比特的解码结果会影响后续比特的解码,因为它们之间存在依赖关系。虽然SC译码的实现较为简单,但其计算复杂度较高,随着码长的增加,解码时间会线性增长。 SCL(Successive Cancellation List,逐位取消列表)译码是SC译码的改进版本。它通过引入列表机制,同时处理多个路径,从而增强了错误校正能力,并在一定程度上降低了错误率。与SC译码相比,SCL译码虽然需要消耗更多的计算资源,但能够提供更好的性能。 一个完整的MATLAB仿真资源通常包含以下内容: 编码模块:用于实现极化码的生成,包括码字构造和极化矩阵操作等。 信道模型:用于模拟各种通信信道,例如AWGN(加性高斯白噪声)信道或衰落信道。 SC/SCL译码模块:包含SC译码和SCL译码的算法实现。 误码率(BER)计算:通过比较发送和接收的码字,计算误码率,以评估编码性能。 性能曲线绘制:绘制误码率与信噪比(SNR)之间的关系曲线,展示不同译码策略的性能差异。 使用说明:指导用户如何运行仿真,理解代码结构,以及如何调整参数以进行自定义实验。 代码注
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值