线段树模板题2 洛谷P3373

Description

如题,已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和


Input

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k
操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k
操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果


Output

输出包含若干行整数,即为所有操作3的结果。


Hint

对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000


Solution

这种我居然看了题解才过(还一句一句对)真的无敌恶心,,所以我还是太弱了。。


呃这道题其实就是一个优先级的问题比较难想(对我这种垃圾肯定理所当然地想不出来啊为什么我那么垃圾啊),然后就是乘法优先的话每一次加法的lazy_tag就要先乘乘法的LAZY_TAG,维护两个tag的过程也是要乘乘法的LAZY_TAG,就是乘法的优先级,当一个数同时有乘法和加法的tag的时候就不会出错,因为一直选择的乘法优先,值得注意的是当乘法的Update的过程中,lazy_tag也要跟着LAZY_TAG进行修改因为乘法优先,当lazy_tag的值等于零的时候就不影响,当lazy_tag有值的时候其道理就跟X_Download的时候要乘乘法的LAZY_TAG的道理是一样的了。


注意事项:
1.写代码的过程中要区分now,leftt[now],rightt[now],不然总是卡在这种小错上面迟早要完。。。
2.少看题解对身体好。。
3.%数要打括号。
4.我是傻逼!!!!!!!!!!啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊!!!!!!!!!!!!!!!!!!!

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mid ((l+r)>>1)
#define maxn 400005
#define int long long
using namespace std;
int leftt[maxn],rightt[maxn],TOL_seg[maxn],aa[maxn],LAZY_TAG[maxn],lazy_tag[maxn];
int root,newp,n,m,k,p,a,b,c;
void X_Upload(int now){
    TOL_seg[now]=(TOL_seg[leftt[now]]+TOL_seg[rightt[now]])%p;
}
void X_Download(int now,int l,int r){
    TOL_seg[leftt[now]]=(TOL_seg[leftt[now]]*LAZY_TAG[now]+lazy_tag[now]*(mid-l+1))%p;
    TOL_seg[rightt[now]]=(TOL_seg[rightt[now]]*LAZY_TAG[now]+lazy_tag[now]*(r-mid))%p;
    LAZY_TAG[leftt[now]]=(LAZY_TAG[leftt[now]]*LAZY_TAG[now])%p;
    LAZY_TAG[rightt[now]]=(LAZY_TAG[rightt[now]]*LAZY_TAG[now])%p;
    lazy_tag[leftt[now]]=(lazy_tag[leftt[now]]*LAZY_TAG[now]+lazy_tag[now])%p;
    lazy_tag[rightt[now]]=(lazy_tag[rightt[now]]*LAZY_TAG[now]+lazy_tag[now])%p;
    lazy_tag[now]=0;
    LAZY_TAG[now]=1;
}
void X_Build(int &now,int l,int r){
    now=++newp;
    if(l==r){
        TOL_seg[now]=aa[l];
        return;
    }
    X_Build(leftt[now],l,mid);
    X_Build(rightt[now],mid+1,r);
    X_Upload(now);
}
int X_Search(int now,int l,int r,int x,int y){
    if(x>r||y<l)return 0;
    if(x<=l&&y>=r){
        return TOL_seg[now];
    }
    X_Download(now,l,r);
    return (X_Search(leftt[now],l,mid,x,y)+X_Search(rightt[now],mid+1,r,x,y))%p;
}
void X_Update(int now,int l,int r,int x,int y,int dx,int z){
    if(x>r||y<l)return;
    if(z==1){
        if(x<=l&&y>=r){
            TOL_seg[now]=(TOL_seg[now]*dx)%p;
            LAZY_TAG[now]=(LAZY_TAG[now]*dx)%p;
            lazy_tag[now]=(lazy_tag[now]*dx)%p;
            return;
        }
        X_Download(now,l,r);
        X_Update(leftt[now],l,mid,x,y,dx,1);
        X_Update(rightt[now],mid+1,r,x,y,dx,1);
        X_Upload(now);
    }
    if(z==2){
        if(x<=l&&y>=r){
            TOL_seg[now]=(TOL_seg[now]+dx*(r-l+1))%p;
            lazy_tag[now]=(lazy_tag[now]+dx)%p;
            return;
        }
        X_Download(now,l,r);
        X_Update(leftt[now],l,mid,x,y,dx,2);
        X_Update(rightt[now],mid+1,r,x,y,dx,2);
        X_Upload(now);
    }
}
signed main(){
    for(int i=1;i<maxn;i++){
        LAZY_TAG[i]=1;
    }
    scanf("%lld%lld%lld",&n,&m,&p);
    for(int i=1;i<=n;i++){
        scanf("%lld",&aa[i]);
    }
    X_Build(root,1,n);
    for(int i=1;i<=m;i++){
        scanf("%lld",&k);
        if(k==1){
            scanf("%lld%lld%lld",&a,&b,&c);
            X_Update(root,1,n,a,b,c,1);
        }
        if(k==2){
            scanf("%lld%lld%lld",&a,&b,&c);
            X_Update(root,1,n,a,b,c,2);
        }
        if(k==3){
            scanf("%lld%lld",&a,&b);
            printf("%lld\n",X_Search(root,1,n,a,b));
        }
    }
    return 0;
}
posted @ 2018-11-30 16:55  虚拟北方virtual_north。  阅读(151)  评论(0编辑  收藏  举报