P2023 [AHOI2009]維護序列 題解(線段樹
阿新 • • 發佈:2019-01-08
題目連結
解題思路
線段樹板子。不難,但是...有坑。坑有多深?一頁\(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; }