codevs2216 行星序列

题目描述 Description

“神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始,他就报名参加了“小小宇航员夏令营”,在这里小可可不仅学到了丰富的宇航知识,还参与解决了一些模拟飞行中发现的问题,今天指导老师交给他一个任务,在这次模拟飞行的路线上有N个行星,暂且称它们为一个行星序列,并将他们从1至n标号,在宇宙未知力量的作用下这N个行星的质量是不断变化的,所以他们对飞船产生的引力也会不断变化,小可可的任务就是在飞行途中计算这个行星序列中某段行星的质量和,以便能及时修正飞船的飞行线路,最终到达目的地,行星序列质量变化有两种形式:

1,行星序列中某一段行星的质量全部乘以一个值

2,行星序列中某一段行星的质量全部加上一个值

由于行星的质量和很大,所以求出某段行星的质量和后只要输出这个值模P的结果即可,小可可被这个任务难住了,聪明的你能够帮他完成这个任务吗?

输入描述 Input Description

第一行两个整数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

   注:同一行相邻的两数之间用一个空格隔开,每行开头和末尾没有多余空格

输出描述 Output Description

对每个操作3,按照它在输入中出现的顺序,依次一行输出一个整数表示所求行星质量和

样例输入 Sample Input
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
样例输出 Sample Output
2
35
8
数据范围及提示 Data Size & Hint

100%的数据中,M,N<=100000

40%的数据中,M,N<=10000

/*
区间加、乘,一直学蓝书写线段树,看了别人的题解才发现他的线段树,虽然快但是适用性不强(标记永久化容易出问题),说一下要点:①change和query都要pushdown②修改时同时修改add和sum③pushdown的时候一定同时修改子节点的sum④询问时不需要传递add参数⑤下放乘法标记时先乘后加
*/
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define ll long long
#define fo(i,l,r) for(int i = l;i <= r;i++)
#define fd(i,l,r) for(int i = r;i >= l;i--)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int N = 100050;
ll read(){
    ll x=0,f=1;
    char ch=getchar();
    while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();};
    while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();};
    return x*f;
}
int n,m;
ll sumv[N<<4],addv[N<<4],mulv[N<<4],val[N<<4],mod;
ll cmd,ql,qr,c,ans;
void maintain(int l,int r,int rt){
    sumv[rt] = 0;
    if(r > l) sumv[rt] = (sumv[rt<<1] + sumv[rt<<1|1])%mod;
}
void pushdown(int l,int r,int rt){
    if(addv[rt] || mulv[rt] != 1){
        int m = (l + r) >> 1;
        addv[rt<<1] = (addv[rt<<1]*mulv[rt] + addv[rt])%mod;
        addv[rt<<1|1] = (addv[rt<<1|1]*mulv[rt] + addv[rt])%mod;
        mulv[rt<<1]=(mulv[rt<<1]*mulv[rt])%mod;
        mulv[rt<<1|1]=(mulv[rt<<1|1]*mulv[rt])%mod;
        sumv[rt<<1] = (sumv[rt<<1]*mulv[rt]%mod + addv[rt]*(m-l+1)%mod)%mod;
        sumv[rt<<1|1] = (sumv[rt<<1|1]*mulv[rt]%mod + addv[rt]*(r-m)%mod)%mod;
        addv[rt] = 0;
        mulv[rt] = 1;
    }
}
void change(int l,int r,int rt){
    if(ql <= l && qr >= r){
        if(cmd == 1){
            mulv[rt] = (mulv[rt]*c)%mod;
            addv[rt] = (addv[rt]*c)%mod;
            sumv[rt] = (sumv[rt]*c)%mod;
        }
        else{
            addv[rt] = (addv[rt] + c)%mod;
            sumv[rt] = (sumv[rt] + c*(r-l+1))%mod;
        }
    }else{
        pushdown(l,r,rt);
        int m = (l + r) >> 1;
        if(ql <= m) change(lson);
        if(qr > m) change(rson);
        maintain(l,r,rt);
    }
}
void build(int l,int r,int rt){
    mulv[rt] = 1;addv[rt] = 0;
    if(l==r){
        sumv[rt] = val[l]%mod;
    }else{
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        maintain(l,r,rt);
    }
}
ll query(int l,int r,int rt,ll add){
    if(ql <= l && qr >= r){
        return sumv[rt] % mod;
    }else{
        pushdown(l,r,rt);
        int m = (l + r) >> 1;
        ll ret = 0;
        if(ql <= m) ret += query(lson,add+addv[rt]);
        if(qr > m) ret += query(rson,add+addv[rt]);
        return ret % mod;
    }
}
int main(){
    n = read();
    mod = read();
    fo(i,1,n) val[i] = read();
    build(1,n,1);
    m = read();
    fo(i,1,m){
        cmd = read();ql=read();qr=read();
        if(cmd != 3){
            c=read();
            change(1,n,1);
        }else{
            ans = query(1,n,1,0);
            printf("%lld\n",ans);
        }
        
    }
    return 0;
} 

 

posted @ 2016-11-06 16:03  ACforever  阅读(148)  评论(0编辑  收藏  举报