BZOJ 1798 (线段树||分块)的标记合并

Posted on 2016-05-09 15:32  yyjxx2010xyu  阅读(193)  评论(0编辑  收藏  举报

我原来准备做方差的。。

结果发现不会维护两个标记。。

就是操作变成一个 a*x+b ,每次维护a , b 即可

加的时候a=1 ,b=v

乘的时候a=v ,b=0

  1 #include <cstdio>
  2 const long long Maxn=100010;
  3 
  4 long long a[Maxn],n,P,l,r,c,m,type;
  5 struct Node
  6 {
  7     long long mul,add,sum,len;
  8 }tree[Maxn<<2];
  9 
 10 inline void Change(long long o,long long mul,long long add)
 11 {
 12     tree[o].mul=(tree[o].mul*mul)%P;
 13     tree[o].add=(tree[o].add*mul+add)%P;
 14     tree[o].sum=(tree[o].sum*mul+tree[o].len*add)%P;
 15 }
 16 inline void push_down(long long o)
 17 {
 18     Change(o<<1,tree[o].mul,tree[o].add);
 19     Change(o<<1|1,tree[o].mul,tree[o].add);
 20     tree[o].mul=1; tree[o].add=0;
 21 }
 22 inline void push_up(long long o)
 23 {
 24     tree[o].sum=(tree[o<<1].sum+tree[o<<1|1].sum)%P;
 25     tree[o].len=tree[o<<1].len+tree[o<<1|1].len;
 26 }
 27 void Build(long long o,long long l,long long r)
 28 {
 29     tree[o].mul=1; tree[o].add=0;
 30     if (l==r) {tree[o].sum=a[l]; tree[o].len=1; return;}
 31     long long mid=(l+r)>>1;
 32     Build(o<<1,l,mid),Build(o<<1|1,mid+1,r);
 33     push_up(o);
 34 }
 35 void Mul(long long o,long long l,long long r,long long p,long long q,long long v)
 36 {
 37     if (l==p && r==q)
 38     {
 39         Change(o,v,0);
 40         return;
 41     }
 42     push_down(o);
 43     long long mid=(l+r)>>1;
 44     if (q<=mid) Mul(o<<1,l,mid,p,q,v);
 45     if (p>=mid+1) Mul(o<<1|1,mid+1,r,p,q,v);
 46     if (p<=mid && q>=mid+1) 
 47         Mul(o<<1,l,mid,p,mid,v),Mul(o<<1|1,mid+1,r,mid+1,q,v);
 48     push_up(o);
 49 }
 50 void Add(long long o,long long l,long long r,long long p,long long q,long long v)
 51 {
 52     if (l==p && r==q)
 53     {
 54         Change(o,1,v);
 55         return;
 56     }
 57     push_down(o);
 58     long long mid=(l+r)>>1;
 59     if (q<=mid) Add(o<<1,l,mid,p,q,v);
 60     if (p>=mid+1) Add(o<<1|1,mid+1,r,p,q,v);
 61     if (p<=mid && q>=mid+1) 
 62         Add(o<<1,l,mid,p,mid,v),Add(o<<1|1,mid+1,r,mid+1,q,v);
 63     push_up(o);
 64 }
 65 long long Sum(long long o,long long l,long long r,long long p,long long q)
 66 {
 67     if (l==p && r==q) return tree[o].sum;
 68     long long mid=(l+r)>>1;
 69     push_down(o);
 70     if (q<=mid) return Sum(o<<1,l,mid,p,q);
 71     if (p>=mid+1) return Sum(o<<1|1,mid+1,r,p,q);
 72     if (p<=mid && q>=mid+1) 
 73         return (Sum(o<<1,l,mid,p,mid)+Sum(o<<1|1,mid+1,r,mid+1,q))%P;
 74 }
 75 int main()
 76 {
 77     // freopen("c.in","r",stdin);
 78     scanf("%lld%lld",&n,&P);
 79     for (long long i=1;i<=n;i++) scanf("%lld",&a[i]);
 80     Build(1,1,n);
 81     scanf("%lld",&m);
 82     for (long long i=1;i<=m;i++)
 83     {
 84         scanf("%lld",&type);
 85         if (type==1) 
 86         {
 87             scanf("%lld%lld%lld",&l,&r,&c);
 88             Mul(1,1,n,l,r,c);
 89         }
 90         if (type==2) 
 91         {
 92             scanf("%lld%lld%lld",&l,&r,&c);
 93             Add(1,1,n,l,r,c);
 94         }
 95         if (type==3) 
 96         {
 97             scanf("%lld%lld",&l,&r);
 98             printf("%lld\n",Sum(1,1,n,l,r));
 99         }
100     }
101     return 0;
102 }
线段树

 UPD:2016.6.14

突然发现好久没有写过分块了,想到这道可以分块,push_up写成push_down了..

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <cstring>
  4 #include <iostream>
  5 #define LL long long
  6 using namespace std;
  7 const LL Maxn=600010;
  8 const LL Inf=0x3f3f3f3f;
  9 LL a[Maxn],n,P,l,r,c,m,type,Block[Maxn];
 10 struct Node
 11 {
 12     LL mul,add,len,sum;
 13 }tree[Maxn];
 14  
 15 inline void Change(LL o,LL mul,LL add)
 16 {
 17     tree[o].mul=(tree[o].mul*mul)%P;
 18     tree[o].add=(tree[o].add*mul+add)%P;
 19     tree[o].sum=(tree[o].sum*mul+tree[o].len*add)%P;
 20 }
 21 inline void push_down(LL o)
 22 {
 23     for (;Block[o]==Block[o-1];o--);
 24     for (LL i=o;Block[o]==Block[i];i++) a[i]=(a[i]*tree[Block[i]].mul+tree[Block[i]].add)%P;
 25     tree[Block[o]].mul=1,tree[Block[o]].add=0;
 26 }
 27 
 28 inline void push_up(LL o)
 29 {
 30     tree[Block[o]].sum=0;
 31     for (;Block[o]==Block[o-1];o--);
 32     for (LL i=o;Block[o]==Block[i];i++) tree[Block[o]].sum=(tree[Block[o]].sum+a[i])%P;
 33 }
 34 void Mul(LL p,LL q,LL v)
 35 {
 36     if (Block[p]==Block[q])
 37     {
 38         push_down(p);
 39         for (LL i=p;i<=q;i++) a[i]=(a[i]*v)%P; 
 40         push_up(p);
 41         return;
 42     }
 43     for (LL i=Block[p]+1;i<Block[q];i++) Change(i,v,0);
 44     push_down(p),push_down(q);
 45     for (LL i=p;Block[i]==Block[p];i++) a[i]=(a[i]*v)%P;
 46     for (LL i=q;Block[i]==Block[q];i--) a[i]=(a[i]*v)%P;
 47     push_up(p),push_up(q);
 48 }
 49 
 50 void Add(LL p,LL q,LL v)
 51 {
 52     if (Block[p]==Block[q])
 53     {
 54         push_down(p);
 55         for (LL i=p;i<=q;i++) a[i]=(a[i]+v)%P; 
 56         push_up(p);
 57         return;
 58     }
 59     for (LL i=Block[p]+1;i<Block[q];i++) Change(i,1,v);
 60     push_down(p),push_down(q);
 61     for (LL i=p;Block[i]==Block[p];i++) a[i]=(a[i]+v)%P;
 62     for (LL i=q;Block[i]==Block[q];i--) a[i]=(a[i]+v)%P;
 63     push_up(p),push_up(q);
 64 }
 65 LL Sum(LL p,LL q)
 66 {
 67     LL ret=0;
 68     if (Block[p]==Block[q]) 
 69     {
 70         push_down(p);
 71         for (LL i=p;i<=q;i++) ret=(ret+a[i])%P;
 72         return ret;
 73     }
 74     for (LL i=Block[p]+1;i<Block[q];i++) ret=(ret+tree[i].sum)%P;
 75     push_down(p),push_down(q);
 76     for (LL i=p;Block[i]==Block[p];i++) ret=(ret+a[i])%P;
 77     for (LL i=q;Block[i]==Block[q];i--) ret=(ret+a[i])%P;
 78     return ret;
 79 }
 80 int main()
 81 {
 82     scanf("%lld%lld",&n,&P);
 83     for (LL i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]%=P;
 84     LL pos=(LL)sqrt(n);
 85     for (LL i=1;i<=n;i++) Block[i]=(i-1)/pos+1;
 86     memset(tree,0,sizeof(tree));
 87     for (LL i=1;i<=n;i++) tree[Block[i]].len++;
 88     for (LL i=1;i<=n;i++) tree[Block[i]].mul=1;
 89     for (LL i=1;i<=n;i++) tree[Block[i]].sum=(tree[Block[i]].sum+a[i])%P;
 90 
 91     scanf("%lld",&m);
 92     for (LL i=1;i<=m;i++)
 93     {
 94         scanf("%lld",&type);
 95         if (type==1) 
 96         {
 97             scanf("%lld%lld%lld",&l,&r,&c);
 98             Mul(l,r,c);
 99         }
100         if (type==2) 
101         {
102             scanf("%lld%lld%lld",&l,&r,&c);
103             Add(l,r,c);
104         }
105         if (type==3) 
106         {
107             scanf("%lld%lld",&l,&r);
108             printf("%lld\n",Sum(l,r));
109         }
110     }
111     return 0;
112 }
分块