bzoj 1798 Seq 维护序列seq —— 线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1798

这题还4A...

注意:cnt 从1开始;各种模 p;乘法标记初始值是 1;可能乘 0。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
int const xn=1e5+5;
int n,a[xn],cnt,ls[xn<<1],rs[xn<<1],sum[xn<<1],lzy[xn<<1],ml[xn<<1],p;
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=0; ch=getchar();}
  while(ch>=‘0‘&&ch<=‘9‘)ret=(ret<<3)+(ret<<1)+ch-‘0‘,ch=getchar();
  return f?ret:-ret;
}
int upt(int x){while(x>=p)x-=p; while(x<0)x+=p; return x;}
void build(int x,int l,int r)
{
  ml[x]=1;//
  if(l==r){sum[x]=a[l]; return;}
  ls[x]=++cnt; rs[x]=++cnt;
  build(ls[x],l,mid); build(rs[x],mid+1,r);
  sum[x]=upt(sum[ls[x]]+sum[rs[x]]);
}
void turn(int x,int c){sum[x]=(ll)sum[x]*c%p; lzy[x]=(ll)lzy[x]*c%p; ml[x]=(ll)ml[x]*c%p;}
void pushdown(int x,int l,int r)
{
  if(ml[x]!=1)//0
    {
      int v=ml[x]; ml[x]=1;//1
      turn(ls[x],v); turn(rs[x],v);
    }
  if(lzy[x])
    {
      int v=lzy[x]; lzy[x]=0;
      sum[ls[x]]=(sum[ls[x]]+(ll)(mid-l+1)*v)%p; lzy[ls[x]]=upt(lzy[ls[x]]+v);
      sum[rs[x]]=(sum[rs[x]]+(ll)(r-mid)*v)%p; lzy[rs[x]]=upt(lzy[rs[x]]+v);
    }
}
void mul(int x,int l,int r,int L,int R,int c)
{
  if(l>=L&&r<=R){turn(x,c); return;}
  pushdown(x,l,r);
  if(mid>=L)mul(ls[x],l,mid,L,R,c);
  if(mid<R)mul(rs[x],mid+1,r,L,R,c);
  sum[x]=upt(sum[ls[x]]+sum[rs[x]]);
}
void add(int x,int l,int r,int L,int R,int c)
{
  if(l>=L&&r<=R){sum[x]=(sum[x]+(ll)(r-l+1)*c)%p; lzy[x]=upt(lzy[x]+c); return;}
  pushdown(x,l,r);
  if(mid>=L)add(ls[x],l,mid,L,R,c);
  if(mid<R)add(rs[x],mid+1,r,L,R,c);
  sum[x]=upt(sum[ls[x]]+sum[rs[x]]);
}
int query(int x,int l,int r,int L,int R)
{
  if(l>=L&&r<=R)return sum[x];
  pushdown(x,l,r); int ret=0;
  if(mid>=L)ret=upt(ret+query(ls[x],l,mid,L,R));
  if(mid<R)ret=upt(ret+query(rs[x],mid+1,r,L,R));
  return ret;
}
int main()
{
  n=rd(); p=rd();
  for(int i=1;i<=n;i++)a[i]=rd()%p;
  build(++cnt,1,n);
  int m=rd();
  for(int i=1,tp,l,r,c;i<=m;i++)
    {
      tp=rd(); l=rd(); r=rd();
      if(tp==1)c=rd()%p,mul(1,1,n,l,r,c);
      if(tp==2)c=rd()%p,add(1,1,n,l,r,c);
      if(tp==3)printf("%d\n",query(1,1,n,l,r));
    }
  return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9887201.html

时间: 2024-08-27 15:24:01

bzoj 1798 Seq 维护序列seq —— 线段树的相关文章

BZOJ 1798 [Ahoi2009]维护序列seq (线段树)

题意 对于一个给定的序列有3种操作: 1.给一个区间的数乘c 2.给一个区间的数加c 3.查询区间和. 思路 就是普通的线段树区间更新,因为更新操作有两种,维护两个延迟标记就可以了,不过要注意乘和加在更新时相互之间的关系,在更新乘的时候之前加的数也要相应的乘,更新加的时候之前所乘的数没有改变. 代码 #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm>

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)询问数列

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树多重标记下传)

www.cnblogs.com/shaokele/ bzoj1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值

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)询问数列中的一段数的和

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[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

bzoj 1798 [Ahoi2009]Seq 维护序列seq(线段树+传标)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1798 [题意] 给定一个序列,要求提供区间乘/加,以及区间求和的操作 [思路] 线段树+传标. 下传标记的方式可以类比这里 click here [代码] 1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio>

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

题意:链接 方法:线段树 解析: 俩标记sb题 更新乘的时候更新加 完了 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define N 100010 using namespace std; typedef

【BZOJ 1798】 [Ahoi2009]Seq 维护序列seq

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).第三行有一个整

bzoj 1798 [Ahoi2009]Seq 维护序列seq

原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798 线段树区间更新: 1. 区间同同时加上一个数 2. 区间同时乘以一个数 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstdio> 5 #define lc root<<1 6 #define rc root<<1|1