BZOJ 1798 [Ahoi2009]Seq 维护序列——线段树

来源:互联网 发布:numpy攻略 源码 编辑:程序博客网 时间:2024/04/30 05:37

1798: [Ahoi2009]Seq 维护序列seq

题目描述
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
输入
第一行两个整数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)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
输出
对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
解题思路
这题是很裸的线段树的题目,就是又有加又有乘,于是线段树就有了两个tag,传tag的时候稍微推一下。这道题我A了很久,半个月左右QAQ,最主要线段树没理解好,记住:传到x点tag的同时修正x点。嗯,这个很重要。

#include<cstdio>#define LL long longusing namespace std;const int maxn=100005;struct jz{    int L,R;    LL tag1,tag2,w;}a[4*maxn];inline int _read(){    int num=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();    return num;}int tt,n,m,w[maxn];void build(int x,int L,int R){    a[x].L=L;a[x].R=R;a[x].tag1=1;    if (L==R){a[x].w=(LL)w[L]%tt;return;}    int mid=L+R>>1;    build(x*2,L,mid);build(x*2+1,mid+1,R);    a[x].w=(a[x*2].w+a[x*2+1].w)%tt;}void Pushdown(int x){    if (a[x].L==a[x].R) return;    int tag1=a[x].tag1,tag2=a[x].tag2;a[x].tag1=1;a[x].tag2=0;    a[x*2].w=(a[x*2].w*tag1+(LL)tag2*(a[x*2].R-a[x*2].L+1))%tt;    a[x*2+1].w=(a[x*2+1].w*tag1+(LL)tag2*(a[x*2+1].R-a[x*2+1].L+1))%tt;    a[x*2].tag1=(a[x*2].tag1*tag1)%tt;    a[x*2+1].tag1=(a[x*2+1].tag1*tag1)%tt;    a[x*2].tag2=(a[x*2].tag2*tag1+tag2)%tt;    a[x*2+1].tag2=(a[x*2+1].tag2*tag1+tag2)%tt;}void change(int x,int L,int R,int c,int p){    if (a[x].L==L&&a[x].R==R){        a[x].tag1=(a[x].tag1*c)%tt;        a[x].tag2=(a[x].tag2*c+p)%tt;        a[x].w=(a[x].w*c+(a[x].R-a[x].L+1)*p)%tt;        return;    }    Pushdown(x);    int mid=a[x].L+a[x].R>>1;    if (R<=mid) change(x*2,L,R,c,p);    else if (L>mid) change(x*2+1,L,R,c,p);    else{change(x*2,L,mid,c,p);change(x*2+1,mid+1,R,c,p);}    a[x].w=(a[x*2].w+a[x*2+1].w)%tt;}int query(int x,int L,int R){    if (a[x].L==L&&a[x].R==R) return a[x].w;    Pushdown(x);    int mid=a[x].L+a[x].R>>1;    if (R<=mid) return query(x*2,L,R);    else if (L>mid) return query(x*2+1,L,R);    else return (query(x*2,L,mid)+query(x*2+1,mid+1,R))%tt;}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    n=_read();tt=_read();    for (int i=1;i<=n;i++) w[i]=_read();    build(1,1,n);    m=_read();    while (m--){        int t=_read(),x=_read(),y=_read(),z;        if (t==1){z=_read();change(1,x,y,z,0);}        if (t==2){z=_read();change(1,x,y,1,z);}        if (t==3) printf("%d\n",query(1,x,y));    }    return 0;}
1 0
原创粉丝点击