【線段樹】COGS 2633
阿新 • • 發佈:2018-12-30
參考部落格,作者:dreaming__ldx,來源:CSDN
【題目大意】
一個長度為n的序列,一開始序列數的權值都是0,有m次操作
支援兩種操作,
1 L R x,給區間[L,R]內,第一個數加x,第二個數加2^2⋅x,第三個數加3^2⋅x...第R-L+1個數加(R−L+1)^2⋅x
2 L R 查詢區間[L,R]內的權值和
每次詢問的答案對2^64取模
【輸入格式】
第一行兩個數n,m,表示序列長度和操作次數
接下來m行,每行描述一個操作,有如下兩種情況:
1 L R x,給區間[L,R]內,第一個數加x,第二個數加2^2⋅x,第三個數加3^2⋅x...第R-L+1個數加(R−L+1)^2⋅x
2 L R 查詢區間[L,R]內的權值和
【輸出格式】
為了減少輸出,你只需要輸出所有答案對2^64取膜之後的異或和。
【樣例輸入】
5 5
1 3 4 1
2 1 5
2 2 2
1 3 3 1
1 2 4 1
【樣例輸出】
5
【提示】
對於10%的資料 n,m<=2000
對於30%的資料 n,m<=10000
對於100%的資料,n,m<=100000,1<=L<=R<=n,0<=x<=1e9
【思路】這裡相當於是區間加一個二次函式。對於一個L到R的修改,第i項相當於是加了((i-(L-1))^2)*x。
這裡用線段樹不好直接維護。考慮把變數分離一下。
如果我們把下標i作為主元,那麼這個函式就可以拆成 i^2 *x + i*(2-2*L) *x + (L-1)^2 *x。
那麼可以把這個函式分成三個部分分開維護。
三個標記分別記錄i^2、i和常數項的係數就好了。
然後三坨就用三個區間和分開來維護。
對於i^2和i,用一個數組預處理一下就行了。
下傳標記的時候乘一乘就好了。unsigned long long 會自動溢位,就是自動對2^64取模。預處理的時候迴圈裡的i也是ull型別!
#include<bits/stdc++.h> #define lc (root<<1) #define rc (root<<1|1) #define mid (T[root].l+T[root].r>>1) #define ull unsigned long long using namespace std; const ull maxn=1e5+5; ull n,m,L,R,op,x; ull cal[maxn][2],ans=0; struct node{ ull l,r; ull add[3],sum[3]; }T[maxn<<2]; void read(ull &x){ x=0;char ch=getchar(); while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); } void build(ull root,ull l,ull r){ T[root].l=l,T[root].r=r; if(l==r) return; build(lc,l,mid),build(rc,mid+1,r); } inline void pushup(ull root){ for(ull i=0;i<3;++i) T[root].sum[i]=T[lc].sum[i]+T[rc].sum[i]; } inline void pushnow(ull root,ull w1,ull w2,ull w3){ T[root].sum[0]+=(T[root].r-T[root].l+1)*w1; T[root].sum[1]+=(cal[T[root].r][0]-cal[T[root].l-1][0])*w2; T[root].sum[2]+=(cal[T[root].r][1]-cal[T[root].l-1][1])*w3; T[root].add[0]+=w1; T[root].add[1]+=w2; T[root].add[2]+=w3; } inline void pushdown(ull root){ pushnow(lc,T[root].add[0],T[root].add[1],T[root].add[2]); pushnow(rc,T[root].add[0],T[root].add[1],T[root].add[2]); T[root].add[0]=T[root].add[1]=T[root].add[2]=0; } void update(ull root,ull L,ull R,ull x,ull pos){ if(L<=T[root].l&&R>=T[root].r){ pushnow(root,(ull)(pos-1)*(pos-1)*x,(ull)2*(1-pos)*x,(ull)x); return; } pushdown(root); if(L<=mid) update(lc,L,R,x,pos); if(R>mid) update(rc,L,R,x,pos); pushup(root); } ull query(ull root,ull L,ull R){ if(L<=T[root].l&&R>=T[root].r) return T[root].sum[0]+T[root].sum[1]+T[root].sum[2]; pushdown(root); ull ret=0; if(L<=mid) ret+=query(lc,L,R); if(R>mid) ret+=query(rc,L,R); return ret; } signed main(){ freopen("rneaty.in","r",stdin); freopen("rneaty.out","w",stdout); read(n),read(m); build(1,1,n); for(ull i=1;i<=n;++i){ cal[i][0]=cal[i-1][0]+i; cal[i][1]=cal[i-1][1]+i*i; } while(m--){ read(op),read(L),read(R); if(op==1){ read(x); update(1,L,R,(ull)x,(ull)L); } if(op==2) ans^=query(1,L,R); } cout<<ans<<'\n'; }