luogu1438無聊的數列(區間加等差數列,求一個數的和)
阿新 • • 發佈:2018-12-22
相加 nod 比較 oid 線段 getchar() 使用 修改 只需要
QAQ一道線段樹好題
題目大意:
給定一個有n個數的數列,共m種操作,有兩種操作
\(1\ l\ r\ k\ d\)表示將\(a[l]\)~\(a[r]\)的數加一個以k為首相,d為公差
\(2\ x\)表示求\(a[x]\)是多少
QwQ又是一道不會的題
暴力修改肯定會T飛
如果可以用線段樹進行區間修改呢??
我們考慮,對於一段區間\([l,r]\),我們只需要記錄它的區間的首相和公差,就能將這個標記下傳了
QwQ哇,那可以只使用這個線段樹進行一個標記下傳了(所以沒有up函數)
這裏展示一下pushdown的部分
\(f[root].d\)表示公差,\(f[root].first\)表示首相
void pushdown(int root,int l,int r) { if (f[root].d || f[root].first) { int mid = (l+r) >> 1; f[2*root].d+=f[root].d; f[2*root+1].d+=f[root].d; f[2*root].first+=f[root].first; f[2*root+1].first+=(f[root].first+(mid-l+1)*f[root].d); f[root].d=f[root].first=0; } }
因為,等差數列相加依然是等差數列,所以對於公差和首相,可以直接加
對一個區間的話\([l,r]\),\([l,mid]\)這部分可以直接進行加法,而對於\([mid+1,r]\)稍微操作一下,修改首相即可
求和什麽的,也比較簡單
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<cstdlib> #include<queue> #include<map> #include<vector> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)) {if (ch==‘-‘) f=-1;ch=getchar();} while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();} return x*f; } const int maxn = 100010; struct Node{ int d,first; }; Node f[4*maxn]; Node add[4*maxn]; int a[4*maxn]; int n,m; void pushdown(int root,int l,int r) { if (f[root].d || f[root].first) { int mid = (l+r) >> 1; f[2*root].d+=f[root].d; f[2*root+1].d+=f[root].d; f[2*root].first+=f[root].first; f[2*root+1].first+=(f[root].first+(mid-l+1)*f[root].d); f[root].d=f[root].first=0; } } void update(int root,int l,int r,int x,int y,int first,int d) { if (x<=l && r<=y){ f[root].d+=d; f[root].first+=(l-x)*d+first; return ; } pushdown(root,l,r); int mid = (l+r) >> 1; if (x<=mid) update(2*root,l,mid,x,y,first,d); if (y>mid) update(2*root+1,mid+1,r,x,y,first,d); } int query(int root,int l,int r,int pos) { if (l==r) { return a[l]+f[root].first; } pushdown(root,l,r); int mid = (l+r) >> 1; if (pos<=mid) return query(2*root,l,mid,pos); if (pos>mid) return query(2*root+1,mid+1,r,pos); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=m;i++) { int opt; opt=read(); if (opt==1) { int l,r,k,d; l=read(),r=read(),k=read(),d=read(); update(1,1,n,l,r,k,d); } else { int x=read(); printf("%d\n",query(1,1,n,x));. } } return 0; }
luogu1438無聊的數列(區間加等差數列,求一個數的和)