BZOJ1798: [Ahoi2009]Seq 维护序列seq

来源:互联网 发布:史蒂芬库里 知乎 编辑:程序博客网 时间:2024/06/03 06:21

Description

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
Input

第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
Output

对每个操作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

HINT

【样例说明】

初始时数列为(1,2,3,4,5,6,7)。
经过第1次操作后,数列为(1,10,15,20,25,6,7)。
对第2次操作,和为10+15+20=45,模43的结果是2。
经过第3次操作后,数列为(1,10,24,29,34,15,16}
对第4次操作,和为1+10+24=35,模43的结果是35。
对第5次操作,和为29+34+15+16=94,模43的结果是8。

测试数据规模如下表所示

数据编号 1 2 3 4 5 6 7 8 9 10
N= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000
M= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000

题目传送门

第一反应是莫队,看来我学数据结构都快学傻了…
O(100000^3/5)是2亿多,那待修莫队就肯定跑不过去
所以要用线段树的lazy标记

最大的坑点还是要注意乘法标记和加法标记的顺序
一定要先加后乘

winter is coming凛冬将至                          ——《Game of Thrones》

代码如下:

#include<cmath>#include<cstdio>#include<cstring>#include<cstdlib> #include<algorithm>using namespace std;typedef long long ll;int n;ll mod;struct trnode{    int l,r,lc,rc;    ll c,mul,add;}tr[1110000];int trlen;ll a[110000];void bt(int l,int r){    int now=++trlen;    tr[now].l=l;tr[now].r=r;tr[now].c=0;    tr[now].lc=tr[now].rc=-1;    tr[now].mul=1,tr[now].add=0;    if(l==r){tr[now].c=a[l]%mod;return ;}    if(l<r){        int mid=(l+r)/2;        tr[now].lc=trlen+1;bt(l,mid);        tr[now].rc=trlen+1;bt(mid+1,r);    }    tr[now].c=tr[tr[now].lc].c+tr[tr[now].rc].c;}void lazy(int x){    int lc=tr[x].lc,rc=tr[x].rc;    int l=tr[x].l,r=tr[x].r;int mid=(l+r)/2;    if(lc!=-1){        tr[lc].c=(tr[lc].c*tr[x].mul)%mod;        tr[lc].c=(tr[lc].c+tr[x].add*(mid-l+1))%mod;        tr[lc].mul=(tr[lc].mul*tr[x].mul)%mod;        tr[lc].add=(tr[lc].add*tr[x].mul)%mod;        tr[lc].add=(tr[lc].add+tr[x].add)%mod;    }    if(rc!=-1){        tr[rc].c=(tr[rc].c*tr[x].mul)%mod;        tr[rc].c=(tr[rc].c+tr[x].add*(r-mid))%mod;        tr[rc].mul=(tr[rc].mul*tr[x].mul)%mod;        tr[rc].add=(tr[rc].add*tr[x].mul)%mod;        tr[rc].add=(tr[rc].add+tr[x].add)%mod;    }    tr[x].mul=1;tr[x].add=0;}void jia(int now,int l,int r,ll c){    if(l==tr[now].l&&tr[now].r==r){        tr[now].c=(tr[now].c+(r-l+1)*c)%mod;        tr[now].add=(tr[now].add+c)%mod;        return ;    }    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;    lazy(now);    if(r<=mid)jia(lc,l,r,c);    else if(mid+1<=l)jia(rc,l,r,c);    else{        jia(lc,l,mid,c);        jia(rc,mid+1,r,c);    }    tr[now].c=(tr[lc].c+tr[rc].c)%mod;}void cheng(int now,int l,int r,ll c){    if(l==tr[now].l&&r==tr[now].r){        tr[now].c=(tr[now].c*c)%mod;        tr[now].add=(tr[now].add*c)%mod;        tr[now].mul=(tr[now].mul*c)%mod;        return ;    }    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;    lazy(now);    if(r<=mid)cheng(lc,l,r,c);    else if(mid+1<=l)cheng(rc,l,r,c);    else{        cheng(lc,l,mid,c);        cheng(rc,mid+1,r,c);    }    tr[now].c=(tr[lc].c+tr[rc].c)%mod;}ll findsum(int now,int l,int r){    if(l==tr[now].l&&r==tr[now].r){        lazy(now);        return tr[now].c%mod;    }    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;    lazy(now);    if(r<=mid)return findsum(lc,l,r);    else if(mid+1<=l)findsum(rc,l,r);    else return (findsum(lc,l,mid)%mod+findsum(rc,mid+1,r)%mod)%mod;}int main(){    scanf("%d%lld",&n,&mod);    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);    trlen=0;bt(1,n);    int m;    scanf("%d",&m);    while(m--){        int q,l,r;        scanf("%d%d%d",&q,&l,&r);        if(q==3){printf("%lld\n",findsum(1,l,r)%mod);continue;}        ll c;        scanf("%lld",&c);        if(q==2)jia(1,l,r,c);        else cheng(1,l,r,c);    }    return 0;}

by_lmy

原创粉丝点击