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

Posted zinn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
",query(1,1,n,l,r));
    }
  return 0;
}

 

以上是关于bzoj 1798 Seq 维护序列seq —— 线段树的主要内容,如果未能解决你的问题,请参考以下文章

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

BZOJ1798 [Ahoi2009]Seq 维护序列seq

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

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

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树)

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