BZOJ1798行星序列

这篇博客介绍了如何利用线段树解决[AHOI2009]行星序列的问题,其中包括对行星质量的乘法和加法操作,并给出了样例输入和输出。博主分享了实现算法的思路,提到了双标记线段树,并提供了代码实现。
摘要由CSDN通过智能技术生成
  1. [AHOI2009] 行星序列
    ★★★ 输入文件:seqb.in 输出文件:seqb.out 简单对比
    时间限制:2 s 内存限制:1280 MB
    【题目描述】
    “神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小宇航员夏令营”,在这里小可可不仅学到了丰富的宇航知识,还参与解决了一些模拟飞行中发现的问题,今天指导老师交给他一个任务,在这次模拟飞行的路线上有N个行星,暂且称它们为一个行星序列,并将他们从1至n标号,在宇宙未知力量的作用下这N个行星的质量是不断变化的,所以他们对飞船产生的引力也会不断变化,小可可的任务就是在飞行途中计算这个行星序列中某段行星的质量和,以便能及时修正飞船的飞行线路,最终到达目的地,行星序列质量变化有两种形式:
    1,行星序列中某一段行星的质量全部乘以一个值
    2,行星序列中某一段行星的质量全部加上一个值
    由于行星的质量和很大,所以求出某段行星的质量和后只要输出这个值模P的结果即可,小可可被这个任务难住了,聪明的你能够帮他完成这个任务吗?
    【输入格式】
    第一行两个整数N和P(1<=p<=1000000000);
    第二行含有N个非负整数,从左到右依次为a1,a2,…………,an(0<=ai<。100000000,1<=i<=n),其中ai表示第i个行星的质量:
    第三行有一个整数m,表示模拟行星质量变化以及求质量和等操作的总次数。从第四行开始每行描述一个操作,输入的操作有以下三种形式:
    操作1:1 t g c 表示把所有满足t<=i<=g的行星质量ai改为ai*c
    操作2:2 t g c 表示把所有满足t<=i<=g的行星质量ai改为ai+c
    操作3:3 t g 表示输出所有满足t<=i<=g的ai的和模p的值
    其中:1<=t<=g<=N,0<=c<=10000000
    注:同一行相邻的两数之间用一个空格隔开,每行开头和末尾没有多余空格
    【输出格式】
    对每个操作3,按照它在输入中出现的顺序,依次一行输出一个整数表示所求行星质量和
    【样例输入】
    7 43
    1 2 3 4 5 6 7
    5
    1 2 5 5
    3 2 4
    2 3 7 9
    3 1 3
    3 4 7
    【样例输出】
    2
    35
    8
    【提示】
    100%的数据中,M,N<=100000
    40%的数据中,M,N<=10000
    【来源】
    AHOI2009
    双标记线段树,在开struct的时候记录一下每个节点的左区间和右区间,方便后续的乘和加操作。。同时开两个变量记录乘法标记和加法标记。
    乘法操作时,将c乘以乘法标记%p赋值给乘法标记
    加法操作时,将c乘以乘法标记加上加法标记%p赋值给加法标记
    初始化加法标记为0,乘法标记为1
    预处理完后,无论是加法还是乘法操作,都是先加后乘,不会出现多加或多乘的情况。。
    附上本蒟蒻的代码:
#include<cstdio>
using namespace std;
struct edge
{
    int lson,rson;
    long long value,mul,add;
};
edge node[400001];
long long a[400001];
int n,p;

int read()
{
    int w=0,c=1;
    char ch=getchar();
    while (ch<'0' || ch>'9')
      {
        if (ch=='-')
          c=-1;
        ch=getchar();
      }
    while (ch>='0' && ch<='9')
      {
        w=w*10+ch-'0';
        ch=getchar();
      }
    return w*c;
}

void update(int s)
{
    node[s].value=(node[s*2].value+node[s*2+1].value)%p;
}

void build(int s,int l,int r)
{
    node[s].lson=l;
    node[s].rson=r;
    node[s].mul=1;
    if (l==r)
      {
        node[s].value+=a[l]%p;
        return;
      }
    build(s*2,l,(l+r)/2);
    build(s*2+1,(l+r)/2+1,r);
    update(s);
}

void pushdown(int s)
{
    long long multiple,addup;
    int t=node[s].rson-node[s].lson+1;
    if (t==1)
      return;
    multiple=node[s].mul;
    addup=node[s].add;
    node[s].mul=1;
    node[s].add=0;
    node[s*2].value=(node[s*2].value*multiple+addup*(t-t/2))%p;
    node[s*2+1].value=(node[s*2+1].value*multiple+addup*(t/2))%p;
    node[s*2].mul=(node[s*2].mul*multiple)%p;
    node[s*2+1].mul=(node[s*2+1].mul*multiple)%p;
    node[s*2].add=(node[s*2].add*multiple+addup)%p;
    node[s*2+1].add=(node[s*2+1].add*multiple+addup)%p;
}

void insert(int s,int x,int y,long long multiple,long long addup)
{
    int mid;
    pushdown(s);
    int l=node[s].lson,r=node[s].rson;
    if (l==x && y==r)
      {
        node[s].value=(node[s].value*multiple+addup*(r-l+1))%p;
        node[s].mul=(node[s].mul*multiple)%p;
        node[s].add=(node[s].add*multiple+addup)%p;
        return;
      }
    mid=(l+r)/2;
    if (y<=mid)
      insert(s*2,x,y,multiple,addup);
    else
      if (x>mid)
        insert(s*2+1,x,y,multiple,addup);
      else
        {
            insert(s*2,x,mid,multiple,addup);
            insert(s*2+1,mid+1,y,multiple,addup);
        }
    update(s);
}

long long query(int s,int x,int y)
{
    int l=node[s].lson,r=node[s].rson,mid;
    long long ans;
    pushdown(s);
    if (l==x && y==r)
      return node[s].value;
    mid=(l+r)/2;
    if (y<=mid)
      ans=query(s*2,x,y);
    else
      if (x>mid)
        ans=query(s*2+1,x,y);
      else
        ans=(query(s*2,x,mid)+query(s*2+1,mid+1,y))%p;
    update(s);
    return ans;
}

int main()
{
    freopen("seqb.in","r",stdin);
    freopen("seqb.out","w",stdout);
    int i,m,q,x,y,z;
    n=read();
    p=read();
    for (i=1;i<=n;i++)
      a[i]=read();
    build(1,1,n);
    m=read();
    for (i=1;i<=m;i++)
      {
        q=read();
        if (q==1)
          {
            x=read();
            y=read();
            z=read();
            insert(1,x,y,z,0);
          }
        if (q==2)
          {
            x=read();
            y=read();
            z=read();
            insert(1,x,y,1,z);
          }
        if (q==3)
          {
            x=read();
            y=read();
            printf("%lld\n",query(1,x,y)%p);
          }
      }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值