乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      P3373 【模板】線段樹 2

       印度阿三17 2019-05-12

      題目來源:洛谷

      題目描述

      如題,已知一個數(shù)列,你需要進行下面三種操作:

      1.將某區(qū)間每一個數(shù)乘上x

      2.將某區(qū)間每一個數(shù)加上x

      3.求出某區(qū)間每一個數(shù)的和

      輸入輸出格式

      輸入格式:

      ?

      第一行包含三個整數(shù)N、M、P,分別表示該數(shù)列數(shù)字的個數(shù)、操作的總個數(shù)和模數(shù)。

      第二行包含N個用空格分隔的整數(shù),其中第i個數(shù)字表示數(shù)列第i項的初始值。

      接下來M行每行包含3或4個整數(shù),表示一個操作,具體如下:

      操作1: 格式:1 x y k 含義:將區(qū)間[x,y]內(nèi)每個數(shù)乘上k

      操作2: 格式:2 x y k 含義:將區(qū)間[x,y]內(nèi)每個數(shù)加上k

      操作3: 格式:3 x y 含義:輸出區(qū)間[x,y]內(nèi)每個數(shù)的和對P取模所得的結(jié)果

      ?

      輸出格式:

      ?

      輸出包含若干行整數(shù),即為所有操作3的結(jié)果。

      ?

      輸入輸出樣例

      輸入樣例#1:?
      5 5 38
      1 5 4 2 3
      2 1 4 1
      3 2 5
      1 2 4 2
      2 3 5 5
      3 1 4
      輸出樣例#1:?
      17
      2

      說明

      時空限制:1000ms,128M

      數(shù)據(jù)規(guī)模:

      對于30%的數(shù)據(jù):N<=8,M<=10

      對于70%的數(shù)據(jù):N<=1000,M<=10000

      對于100%的數(shù)據(jù):N<=100000,M<=100000

      (數(shù)據(jù)已經(jīng)過加強^_^)

      樣例說明:

      故輸出應為17、2(40 mod 38=2)

      ?

      解析:

      這道題難點就在有兩種操作,還要分先后順序。線段樹的基本模板就不多說了。

      用某高贊題解的話來講:

      面對這兩種操作,可以聯(lián)想到線段樹的一個非常好的功能就是lazytag,只計算出確實需要訪問的區(qū)間的真實值,其他的保存在lazytag里面,這樣可以近似O(NlogN)的運行起來。在嘗試著寫了只有一個lazetag的程序之后我們發(fā)現(xiàn)一個lazytag是不能夠解決問題的,那就上兩個,分別表示乘法意義上的lazytag和加法意義上的lazytag。緊接著想到pushdown操作之后我們又發(fā)現(xiàn)必須在向下傳遞lazytag的時候人為地為這兩個lazytag規(guī)定一個先后順序,排列組合一下只有兩種情況:

      ①加法優(yōu)先,即規(guī)定好segtree[root*2].value=((segtree[root*2].value segtree[root].add)*segtree[root].mul)%p,問題是這樣的話非常不容易進行更新操作,假如改變一下add的數(shù)值,mul也要聯(lián)動變成奇奇怪怪的分數(shù)小數(shù)損失精度,我們內(nèi)心是很拒絕的;

      ②乘法優(yōu)先,即規(guī)定好segtree[root*2].value=(segtree[root*2].value*segtree[root].mul segtree[root].add*(本區(qū)間長度))%p,這樣的話假如改變add的數(shù)值就只改變add,改變mul的時候把add也對應的乘一下就可以了,沒有精度損失,看起來很不錯。

      emmm,我調(diào)了很久就對了。

      ?

      參考代碼:

      #include<cstdio>
      #include<iostream>
      #include<cmath>
      #include<cstring>
      #include<algorithm>
      #define N 100010
      #define LL long long
      using namespace std;
      /*
          碼前須知: 
          取余運算對加法,減法,乘法,指數(shù)運算皆成立,但對除法不成立:
          (a   b) % p = (a % p   b % p) % p 
          (a - b) % p = (a % p - b % p) % p 
          (a * b) % p = (a % p * b % p) % p 
          a ^ b % p = ((a % p)^b) % p 
          因此,此規(guī)律運用得當,本題可以降低相當多的時間復雜度。 
      */
      LL a[N],n,m,P;
      struct tree{
          LL l,r;
          LL sum,add,multi;
      }t[N*4];
      void built(LL p,LL l,LL r)
      {
          t[p].multi=1;t[p].add=0;
          t[p].l=l;t[p].r=r;
          if(l==r){
              t[p].sum=a[l];
              return;
          }
          LL mid=(l r)>>1;
          built(p<<1,l,mid);
          built((p<<1)|1,mid 1,r);
          t[p].sum=(t[p<<1].sum t[(p<<1)|1].sum)%P;
      }
      void spread(LL p)
      {
          //乘法優(yōu)先原則運算
          t[p<<1].sum=((t[p].multi*t[p<<1].sum) t[p].add*(t[p<<1].r-t[p<<1].l 1))%P;
          t[(p<<1)|1].sum=((t[p].multi*t[(p<<1)|1].sum) t[p].add*(t[(p<<1)|1].r-t[(p<<1)|1].l 1))%P;
          //維護線段樹,依舊是乘法優(yōu)先原則 
          t[p<<1].multi=(t[p<<1].multi*t[p].multi)%P;
          t[(p<<1)|1].multi=(t[(p<<1)|1].multi*t[p].multi)%P;
          t[p<<1].add=(t[p].add t[p<<1].add*t[p].multi)%P;//之前寫錯,是因為沒有深入體會乘法優(yōu)先 
          t[(p<<1)|1].add=(t[(p<<1)|1].add*t[p].multi t[p].add)%P;
          //刪除延遲標記 
          t[p].add=0;
          t[p].multi=1;
      }
      LL ask(LL p,LL l,LL r)
      {
          if(l<=t[p].l&&t[p].r<=r) return t[p].sum;
          spread(p);
          LL mid=(t[p].l t[p].r)>>1;
          LL val=0;
          if(l<=mid) val=(val ask(p<<1,l,r))%P;
          if(r>mid) val=(val ask((p<<1)|1,l,r))%P;
          return val%P;
      }
      void change(LL p,LL l,LL r,LL k)
      {
          //根據(jù)我們規(guī)定的乘法優(yōu)先原則,此處的加法傳遞函數(shù)應先進行乘法運算 
          if(l<=t[p].l&&t[p].r<=r){
              t[p].add=(t[p].add k)%P;
              t[p].sum=(t[p].sum k*(t[p].r-t[p].l 1))%P;
              return;
          }
          spread(p);
          LL mid=(t[p].l t[p].r)>>1;
          if(l<=mid) change(p<<1,l,r,k);
          if(r>mid) change((p<<1)|1,l,r,k);
          t[p].sum=(t[p<<1].sum t[(p<<1)|1].sum)%P;
      }
      void multiply(LL p,LL l,LL r,LL k)
      {
          if(l<=t[p].l&&t[p].r<=r){
              t[p].sum=(t[p].sum*k)%P;
              t[p].multi=(t[p].multi*k)%P;
              t[p].add=(t[p].add*k)%P;//在某區(qū)間的乘法延遲標記乘上某數(shù)后,自然的其加法
                                      //延遲標記也要乘上去 
              return;
          }
          spread(p);
          LL mid=(t[p].l t[p].r)>>1;
          if(l<=mid) multiply(p<<1,l,r,k);
          if(r>mid) multiply((p<<1)|1,l,r,k);
          t[p].sum=(t[p<<1].sum t[(p<<1)|1].sum)%P;
      }
      int main()
      {
          scanf("%lld%lld%lld",&n,&m,&P);
          for(int i=1;i<=n;i  ) scanf("%lld",&a[i]);
          built(1,1,n);
          while(m--)
          {
              LL l,r,k;
              int flag;
              scanf("%d",&flag);
              if(flag==2){
                  scanf("%lld%lld%lld",&l,&r,&k);
                  change(1,l,r,k);
              }
              else if(flag==3){
                  scanf("%lld%lld",&l,&r);
                  printf("%lld\n",ask(1,l,r));
              }
              else{
                  scanf("%lld%lld%lld",&l,&r,&k);
                  multiply(1,l,r,k);
              }
          }
          return 0;
      }

      2019-05-12?13:39:57

      來源:http://www./content-4-187551.html

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多