1. 程式人生 > >bzoj 2962: 序列操作

bzoj 2962: 序列操作

序列 區間 urn set 列操作 pri des else status

Time Limit: 50 Sec Memory Limit: 256 MB
Submit: 1179 Solved: 392
[Submit][Status][Discuss]

Description

  有一個長度為n的序列,有三個操作1.I a b c表示將[a,b]這一段區間的元素集體增加c,2.R a b表示將[a,b]區間內所有元素變成相反數,3.Q a b c表示詢問[a,b]這一段區間中選擇c個數相乘的所有方案的和mod 19940417的值。

Input

  第一行兩個數n,q表示序列長度和操作個數。
  第二行n個非負整數,表示序列。
  接下來q行每行輸入一個操作I a b c或者 R a b或者Q a b c意義如題目描述。

Output

  對於每個詢問,輸出選出c個數相乘的所有方案的和mod19940417的值。

Sample Input

5 5
1 2 3 4 5
I 2 3 1
Q 2 4 2
R 1 5
I 1 3 -1
Q 1 5 1

Sample Output

40
19940397
樣例說明
  做完第一個操作序列變為1 3 4 4 5。
  第一次詢問結果為3*4+3*4+4*4=40。
  做完R操作變成-1 -3 -4 -4 -5。
  做完I操作變為-2 -4 -5 -4 -5。
  第二次詢問結果為-2-4-5-4-5=-20。

HINT

  100%的數據n<=50000,q<=50000,初始序列的元素的絕對值<=109,I a b c中保證[a,b]是一個合法區間,|c|<=109,R a b保證[a,b]是個合法的區間。Q a b c中保證[a,b]是個合法的區間1<=c<=min(b-a+1,20)。

Source

中國國家隊清華集訓 2012-2013 第三天

碼農級線段樹題目,,, 子樹合並很好想,就是一個卷積; 標記下傳也很好想,我的寫法的話是先下傳正負再下傳add。 正負修改也很好想,把add和tag打一下標記然後把i是奇數的f[]變成它的相反數即可。 就是區間加之後的維護有點難度,要推一推式子,但是這裏我懶得再推一遍了23333。
#include<bits/stdc++.h>
#define ll long long
#define maxn 50005
#define ha 19940417
using namespace std;
int C[maxn][25],n,m,tp,num;
int a[maxn],le,ri,w,ci[25];

inline int add(int x,int y){
    x+=y;
    return x>=ha?x-ha:x;
}

inline void init(){
    C[0][0]=1;
    for(int i=1;i<=n;i++){
        tp=min(i,20);
        C[i][0]=1;
        for(int j=1;j<=tp;j++) C[i][j]=add(C[i-1][j-1],C[i-1][j]);
    }
}

struct node{
    int tag,ad;
    int c[25];
        
    inline void clear(){
        memset(c,0,sizeof(c));
        tag=ad=0;
    }
    
    node operator +(const node &U)const{
        node r;
        r.clear();
        for(int i=0;i<=20;i++) if(c[i])
            for(int j=i;j<=20;j++) if(U.c[j-i])
                r.c[j]=add(r.c[j],c[i]*(ll)U.c[j-i]%ha);
        
        return r;
    }
}b[maxn<<2|1],AN;
char ch;

void build(int o,int l,int r){
    if(l==r){
        b[o].c[0]=1;
        b[o].c[1]=a[l];
        return;
    }
    
    int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    
    b[o]=b[lc]+b[rc];
}

inline void work(int o,int d,int len){
    tp=min(len,20);
    ci[0]=1;
    for(int i=1;i<=tp;i++) ci[i]=ci[i-1]*(ll)d%ha;
    b[o].ad=add(b[o].ad,d);
    
    for(int i=20;i;i--){
        int S=i,T=len;
        for(int j=0;j<i;j++,S--,T--){
            b[o].c[i]=add(b[o].c[i],b[o].c[j]*(ll)ci[i-j]%ha*(ll)C[T][S]%ha);
        }
    }
}

inline void rotate(int o,int len){
    b[o].tag^=1,b[o].ad=ha-b[o].ad;
    for(int i=1;i<=20;i+=2) b[o].c[i]=ha-b[o].c[i];
}

inline void pushdown(int o,int l,int r){
    int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
    if(b[o].tag){
        rotate(lc,mid-l+1);
        rotate(rc,r-mid);
        b[o].tag=0;
    }
    if(b[o].ad){
        work(lc,b[o].ad,mid-l+1);
        work(rc,b[o].ad,r-mid);
        b[o].ad=0;
    }
}

void updateX(int o,int l,int r){
    if(l>=le&&r<=ri){
        work(o,w,r-l+1);		
        return;
    }
    
    int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
    pushdown(o,l,r);
    if(le<=mid) updateX(lc,l,mid);
    if(ri>mid) updateX(rc,mid+1,r);
        
    b[o]=b[lc]+b[rc];
}

void updateY(int o,int l,int r){
    if(l>=le&&r<=ri){
        rotate(o,r-l+1);
        return;
    }
    
    int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
    pushdown(o,l,r);
    if(le<=mid) updateY(lc,l,mid);
    if(ri>mid) updateY(rc,mid+1,r);
    
    b[o]=b[lc]+b[rc];
}

void query(int o,int l,int r){
    if(l>=le&&r<=ri){
        AN=AN+b[o];
        return;
    }
    
    int mid=l+r>>1,lc=o<<1,rc=(o<<1)|1;
    pushdown(o,l,r);
    if(le<=mid) query(lc,l,mid);
    if(ri>mid) query(rc,mid+1,r);
}

int main(){
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=n;i++){
        scanf("%d",a+i);
        a[i]%=ha;
        if(a[i]<0) a[i]+=ha;
    }
    build(1,1,n);
    
    while(m--){
        ch=getchar();
        while(ch!=‘I‘&&ch!=‘R‘&&ch!=‘Q‘) ch=getchar();
        scanf("%d%d",&le,&ri);
        if(ch==‘R‘) updateY(1,1,n);
        else{
            scanf("%d",&w);
            if(ch==‘Q‘){
                AN.clear();
                AN.c[0]=1;
                query(1,1,n);
                printf("%d\n",AN.c[w]);
            }
            else{
                w%=ha;
                if(w<0) w+=ha;
                updateX(1,1,n);
            }
        }
    }
    
    return 0;
}

  

bzoj 2962: 序列操作