1. 程式人生 > >P2023 [AHOI2009]維護序列 題解(線段樹

P2023 [AHOI2009]維護序列 題解(線段樹

題目連結

P2023 [AHOI2009]維護序列

解題思路

線段樹板子。不難,但是...有坑。坑有多深?一頁\(WA\)
由於乘法可能乘\(k=0\),我這種做法可能會使結果產生負數。於是就有了這篇題解。
(詳情見程式碼註釋)

AC程式碼

#include<stdio.h>
#define min(a,b) (a>b?b:a)
#define max(a,b) (a>b?a:b)
typedef long long ll;
int n,m;
ll mod,k,a[500010];
struct Tree{
    int left,right;
    ll data,lazy,mul;
}tree[2000010];
void build(int p,int left,int right){
    tree[p].left=left;
    tree[p].right=right;
    tree[p].mul=1;
    if(left==right){tree[p].data=a[left];return;}
    build(p<<1,left,(left+right)>>1);
    build(p<<1|1,((left+right)>>1)+1,right);
    tree[p].data=(tree[p<<1].data+tree[p<<1|1].data)%mod;
}
void pushdown(int p){
    ll mul=tree[p].mul,lazy=tree[p].lazy;
    tree[p<<1].lazy*=mul;
    tree[p<<1].lazy+=lazy;tree[p<<1].lazy%=mod;
    tree[p<<1].mul*=mul;tree[p<<1].mul%=mod;
    tree[p<<1|1].lazy*=mul;
    tree[p<<1|1].lazy+=lazy;tree[p<<1|1].lazy%=mod;
    tree[p<<1|1].mul*=mul;tree[p<<1|1].mul%=mod;
    tree[p].data*=tree[p].mul;
    tree[p].data+=(tree[p].right-tree[p].left+1)*tree[p].lazy;
    tree[p].data%=mod;
    tree[p].lazy=0;tree[p].mul=1;
}
void add(int left,int right,ll k,int p){
    int l=tree[p].left,r=tree[p].right;
    if(l>right||r<left||p>4*n)return;
    pushdown(p);
    if(l>=left&&r<=right){
        tree[p].lazy+=k;
        tree[p].lazy%=mod;
        return;
    }
    tree[p].data+=k*(min(right,r)-max(left,l)+1);
    tree[p].data%=mod;
    add(left,right,k,p<<1);
    add(left,right,k,p<<1|1);
}
ll multy(int left,int right,ll k,int p){
    int l=tree[p].left,r=tree[p].right;
    if(l>right||r<left||p>4*n)return 0;
    pushdown(p);
    if(l>=left&&r<=right){
        ll temp=tree[p].data*tree[p].mul+tree[p].lazy*(r-l+1);
        tree[p].lazy*=k;tree[p].lazy%=mod;
        tree[p].mul*=k;tree[p].mul%=mod;
        return ((k-1)*temp%mod+mod)%mod;//非常重要!!!!!! 
    }
    ll temp=multy(left,right,k,p<<1)+multy(left,right,k,p<<1|1); 
    tree[p].data+=temp;
    tree[p].data=;
    return temp;
}
ll query(int left,int right,int p){
    int l=tree[p].left,r=tree[p].right;
    if(l>right||r<left||p>4*n)return 0;
    pushdown(p);
    if(l>=left&&r<=right)return tree[p].data;
    return query(left,right,p<<1)+query(left,right,p<<1|1);
}
int main(){
    int s,x,y,i;
    scanf("%d%lld",&n,&mod);
    for(i=1;i<=n;i++)scanf("%lld",&a[i]);
    build(1,1,n);
    scanf("%d",&m);
    while(m--){
        scanf("%d%d%d",&s,&x,&y);
        if(s-3){
            scanf("%lld",&k);
            if(s-1)add(x,y,k,1);
            else multy(x,y,k,1);
        }else printf("%lld\n",query(x,y,1)%mod);
    }
    return 0;
}