BZOJ 1798 维护序列

我偏要先下传加。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100500
using namespace std;
long long ls[maxn<<2],rs[maxn<<2],val[maxn<<2],lazy1[maxn<<2],lazy2[maxn<<2];
long long n,p,m,a,b,c,d,w[maxn],tot=0,root;
void pushup(long long now)
{
    val[now]=(val[ls[now]]+val[rs[now]])%p;
}
void build(long long &now,long long left,long long right)
{
    now=++tot;lazy1[now]=0;lazy2[now]=1;
    if (left==right)
    {
        val[now]=w[left]%p;
        return;
    }
    long long mid=(left+right)>>1;
    build(ls[now],left,mid);
    build(rs[now],mid+1,right);
    pushup(now);
}
void pushdown(long long now,long long left,long long right)
{
    long long mid=(left+right)>>1;
    lazy1[ls[now]]=(lazy1[ls[now]]*lazy2[now]+lazy1[now])%p;
    lazy1[rs[now]]=(lazy1[rs[now]]*lazy2[now]+lazy1[now])%p;
    lazy2[ls[now]]=(lazy2[ls[now]]*lazy2[now])%p;
    lazy2[rs[now]]=(lazy2[rs[now]]*lazy2[now])%p;
    val[ls[now]]=(val[ls[now]]*lazy2[now]+lazy1[now]*(mid-left+1))%p;
    val[rs[now]]=(val[rs[now]]*lazy2[now]+lazy1[now]*(right-mid))%p;
    lazy1[now]=0;lazy2[now]=1;
}
void modify(long long now,long long left,long long right,long long l,long long r,long long type,long long x)
{
    pushdown(now,left,right);
    if ((left==l) && (right==r))
    {
        if (type==1) {lazy1[now]+=x;lazy1[now]%=p;val[now]+=x*(right-left+1);val[now]%=p;}
        else {lazy2[now]*=x;lazy2[now]%=p;lazy1[now]*=x;lazy1[now]%=p;val[now]*=x;val[now]%=p;}
        return;
    }
    long long mid=(left+right)>>1;
    if (r<=mid) modify(ls[now],left,mid,l,r,type,x);
    else if (l>=mid+1) modify(rs[now],mid+1,right,l,r,type,x);
    else
    {
        modify(ls[now],left,mid,l,mid,type,x);
        modify(rs[now],mid+1,right,mid+1,r,type,x);
    }
    pushup(now);
}
long long ask(long long now,long long left,long long right,long long l,long long r)
{
    pushdown(now,left,right);
    if ((left==l) && (right==r))
        return val[now]%p;
    long long mid=(left+right)>>1;
    if (r<=mid) return ask(ls[now],left,mid,l,r)%p;
    else if (l>=mid+1) return ask(rs[now],mid+1,right,l,r)%p;
    else return (ask(ls[now],left,mid,l,mid)+ask(rs[now],mid+1,right,mid+1,r))%p;
}
void work1()
{
    scanf("%lld%lld%lld",&b,&c,&d);
    modify(root,1,n,b,c,2,d);
}
void work2()
{
    scanf("%lld%lld%lld",&b,&c,&d);
    modify(root,1,n,b,c,1,d);
}
void work3()
{
    scanf("%lld%lld",&b,&c);
    printf("%lld\n",ask(root,1,n,b,c)%p);
}
int main()
{
    scanf("%lld%lld",&n,&p);
    for (long long i=1;i<=n;i++)
        scanf("%lld",&w[i]);
    build(root,1,n);
    scanf("%lld",&m);
    for (long long i=1;i<=m;i++)
    {
        scanf("%lld",&a);
        if (a==1) work1();
        else if (a==2) work2();
        else work3();
    }
    return 0;
}
时间: 2024-12-19 00:17:02

BZOJ 1798 维护序列的相关文章

bzoj 1798 维护序列seq

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798 题解: 高级一点的线段树,加上了区间乘法运算,则需要增加一个数组mulv记录乘的因数,在下放更新sumv和addv值的都时候要先乘再加 被蓝书的写法坑了,就一直搞不懂下放和sumv.addv数组的具体用法,导致网上大犇们的程序我基本都看不懂,写完这道题感觉重新学了一遍线段树 1 #include<cstdio> 2 #include<cstring> 3 #defin

bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1798 Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列

【BZOJ】【1798】【AHOI2009】Seq维护序列

线段树 属于线段树中级应用吧…… 要打两种标记:乘法和加法标记.一开始我想着可以像只有加法标记那样,永不下传,查询的时候依次累加就好了.后来发现不会写……只好每次update的时候……遇到标记!下传!query的时候遇到标记!下传!暴力地来搞…… 然后说下下传的细节:先传乘法,后传加法.因为传乘法标记的时候要连sum带add都要一起乘,如果先传add就会多乘…… 1 /************************************************************** 2

1798: [Ahoi2009]Seq 维护序列seq

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 5886  Solved: 2087[Submit][Status][Discuss] Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和

BZOJ 1798 题解

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 5531  Solved: 1946[Submit][Status][Discuss] Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和

bzoj1798: [Ahoi2009]Seq 维护序列seq 2011-12-20

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MB Submit: 497  Solved: 203 [Submit][Status][Discuss] Description 老 师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的

BZOJ1798题解 Seq维护序列题解 双tag裸线段树

BZOJ1798题解 Seq维护序列题解 双tag裸线段树 1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 5549  Solved: 1951[Submit][Status][Discuss] Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)

bzoj 1798 双标记区间修改线段树

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MAXN 100000 4 #define M ((L+R)>>1) 5 #define lc (id<<1) 6 #define rc (id<<1|1) 7 #define LL long long 8 LL C[(MAXN<<2)+15]; 9 LL P,laz1[(MAXN<<2)+15],laz2[(MAXN

bzoj1798[Ahoi2009]Seq 维护序列seq

bzoj1798[Ahoi2009]Seq 维护序列seq 题意: 维护序列,支持区间加.区间乘.区间求和模一个数.序列大小和操作数≤100000 题解: 线段树,加标记和乘标记的处理同bzoj4003.模的时候注意细节. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define m