zoukankan      html  css  js  c++  java
  • 【洛谷 p3373】模板-线段树 2(数据结构--线段树)

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

    解法:(唉 :-(,这题卡住我了......)对于加法和乘法的混合操作,lazy 标记记为 add , mul。

          我们可以把运算全部化为 x*mul+add*(r-l+1) 的模型,其中它的运算有2种情况:
     1.当前为加法,(x*mul+add*(r-l+1))+add'*(r-l+1) →  (x*mul)+(add+add')*(r-l+1),也就是 add+=add';
     2.当前为乘法,(x*mul+add*(r-l+1))*mul' → (x*mul*mul')+(add*(r-l+1)*mul'),也就是 mul*=mul', add*=mul'。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 using namespace std;
      6 #define N 100010
      7 typedef long long LL;
      8 
      9 int n,m,P,len=0;
     10 struct node
     11 {
     12     int l,r,lc,rc;
     13     LL d,mul,add;
     14 }a[2*N];
     15 
     16 void build(int l,int r)
     17 {
     18     int x=++len;
     19     a[x].l=l,a[x].r=r,a[x].d=0;
     20     a[x].lc=a[x].rc=-1;
     21     a[x].mul=1,a[x].add=0;
     22     if (l<r)
     23     {
     24       int mid=(l+r)>>1;
     25       a[x].lc=len+1,build(l,mid);
     26       a[x].rc=len+1,build(mid+1,r);
     27     }
     28 }
     29 void Pdown(int x,LL mul,LL add)
     30 {
     31     a[x].d=((a[x].d*mul)%P+(add*(a[x].r-a[x].l+1)%P))%P;//r-l+1
     32     a[x].mul=(a[x].mul*mul)%P;
     33     a[x].add=((a[x].add*mul)%P+add)%P;
     34 }
     35 void updata(int x)
     36 {
     37     if (a[x].mul==1 && !a[x].add) return;
     38     int lc=a[x].lc,rc=a[x].rc;
     39     if (lc!=-1) Pdown(lc,a[x].mul,a[x].add);
     40     if (rc!=-1) Pdown(rc,a[x].mul,a[x].add);
     41     a[x].mul=1,a[x].add=0;
     42 }
     43 void addi(int x,int l,int r,LL d)
     44 {
     45     if (a[x].l==l && a[x].r==r)
     46     {
     47       a[x].d=(a[x].d+d*(r-l+1))%P;//r-l+1
     48       a[x].add=(a[x].add+d)%P;
     49       return;
     50     }
     51     updata(x);
     52     int lc=a[x].lc,rc=a[x].rc,mid=(a[x].l+a[x].r)>>1;
     53     if (r<=mid) addi(lc,l,r,d);
     54     else if (l>mid) addi(rc,l,r,d);
     55     else addi(lc,l,mid,d),addi(rc,mid+1,r,d);
     56     a[x].d=(a[lc].d+a[rc].d)%P;//only d
     57 }
     58 void multi(int x,int l,int r,LL d)
     59 {
     60     if (a[x].l==l && a[x].r==r)
     61     {
     62       a[x].d=(a[x].d*d)%P;
     63       a[x].mul=(a[x].mul*d)%P,a[x].add=(a[x].add*d)%P;
     64       return;
     65     }
     66     updata(x);
     67     int lc=a[x].lc,rc=a[x].rc,mid=(a[x].l+a[x].r)>>1;
     68     if (r<=mid) multi(lc,l,r,d);
     69     else if (l>mid) multi(rc,l,r,d);
     70     else multi(lc,l,mid,d),multi(rc,mid+1,r,d);
     71     a[x].d=(a[lc].d+a[rc].d)%P;
     72 }
     73 LL query(int x,int l,int r)
     74 {
     75     updata(x);
     76     if (a[x].l==l && a[x].r==r) return a[x].d;
     77     int lc=a[x].lc,rc=a[x].rc,mid=(a[x].l+a[x].r)>>1;
     78     if (r<=mid) return query(lc,l,r)%P;//%P
     79     else if (l>mid) return query(rc,l,r)%P;
     80     else return (query(lc,l,mid)+query(rc,mid+1,r))%P;
     81 }
     82 int main()
     83 {
     84     LL d; int x,y,k;
     85     scanf("%d%d%d",&n,&m,&P);
     86     build(1,n);
     87     for (int i=1;i<=n;i++)
     88     {
     89       scanf("%lld",&d);
     90       addi(1,i,i,d);
     91     }
     92     while (m--)
     93     {
     94       scanf("%d%d%d",&k,&x,&y);
     95       if (x>y) {int t;t=x,x=y,y=t;}
     96       if (k==1)
     97       {
     98         scanf("%lld",&d);
     99         multi(1,x,y,d%P);
    100       }
    101       else if (k==2)
    102       {
    103         scanf("%lld",&d);
    104         addi(1,x,y,d%P);
    105       }
    106       else printf("%lld
    ",query(1,x,y));
    107     }
    108     return 0;
    109 }
  • 相关阅读:
    【转载】用XML和XSLT来生成静态的HTML页面
    【转载】Lambda表达式(Lambda Expressions)
    [转]打领带的十种方法
    读书笔记
    【转载】用手机的朋友进来看看吧,终身受益啊!!!
    SQL查询出重复出现的数据
    技巧三:字符串格式化
    【Vegas原创】页面自动跳转代码收集
    【Vegas原创】我写的一个安装windowsService的BAT
    【Vegas原创】ASP.NET读取Excel,并以邮件正文方式和附件方式发送实例
  • 原文地址:https://www.cnblogs.com/konjak/p/6072864.html
Copyright © 2011-2022 走看看