bzoj2962 序列操作 線段樹 區間卷積

2022-05-01 20:27:07 字數 2268 閱讀 6250

題目大意:給定乙個n個數的正整數序列,m次操作。支援:1.區間加;2.區間取相反數;3.區間求選c個數的乘積和。

注釋:$1\le n,m\le 5\cdot 10^4$,$1\le c\le 20$。

想法

首先切入點非常明顯,我們發現c只有20。

那麼線段樹上的每個節點維護21個值sum[pos][i]表示在pos節點維護的區間中選取i個數的乘積和。

合併也是容易的:$sum[pos][i]=\sum\limits_^(sum[lson][j]\times sum[rson][i-j])$。

這樣的話如果沒有修改操作,我們就像小白逛公園一樣每次query出來乙個結構體區間,依次將查詢出來的線段樹上的log個區間加在一起即可咯。

緊接著我們考慮帶上修改。

比如說區間加法,單個pos區間加上c。

那麼我們考慮$sum[pos][i]$變成了選取i個數,但是都+c。比如說我們選取出來了$v$序列。

$sum[pos][i]=\sum\limits_^ (a_+c)$

這時我們發現展開之後,比如說有i-1的數的乘積在乙個v序列中會被計算i次,而且保證不同的i序列選取出來的i-1個數的序列集合不完全相同。

故此我們對它擴充套件

$sum[pos][i]=\sum\limits_^ sum[pos][i-j]\times c_^i\times c^$。

然後我們考慮相反數的那個操作,顯然正常的打標記即可因為只有奇數被修改。

像維修數列兩個標記線段樹那樣維護即可。

最後,附上醜陋的**... ...

#include #include #include #include #include using namespace std;

#define ll long long

#define maxn 80010

#define p 19940417

int n,q,c[maxn][21];

inline char nc()

int rd()

namespace segmenttree

; struct segmenttreenodetree[maxn<<2];

#define ls now<<1

#define rs now<<1|1

inline void add(int &x,int y)

inline sumnode merge(segmenttreenode x,segmenttreenode y)

return re;

}

inline void update(int now)

inline void rever(int now)

inline void change(int now,int d)

}inline void pushdown(int now)

if (tree[now].tag)

}inline void buildtree(int now,int l,int r)

int mid=(l+r)>>1;

buildtree(ls,l,mid); buildtree(rs,mid+1,r);

update(now);

}inline void reverse(int now,int l,int r)

pushdown(now);

int mid=(l+r)>>1;

if (l<=mid) reverse(ls,l,r);

if (r>mid) reverse(rs,l,r);

update(now);

}inline void change(int now,int l,int r,int d)

pushdown(now);

int mid=(l+r)>>1;

if (l<=mid) change(ls,l,r,d);

if (r>mid) change(rs,l,r,d);

update(now);

}inline segmenttreenode query(int now,int l,int r,int d)

}void getc()

}using namespace segmenttree;

int main()

} return 0;

}

小結:嘻嘻感謝dad3zz的**/tx。確實是道線段樹的好題。

序列操作 BZOJ2962 線段樹

分析 資料範圍表示 c特別的小 c 20 我們可以考慮nlogn c 2的演算法。線段樹維護區間資訊 f i 表示在 l,r 這段區間中選擇i個數相乘的和。因此,我們可以將區間看成乙個點,在pushup的時候用揹包的方式更新父節點。仔細觀察發現這是卷積 剩下的就是一些優化了.附上 include i...

BZOJ2962 序列操作

題目大意 給定n個數,要求支援區間加,區間取相反數,區間查詢任意選c c 20 個數的所有方案中乘積的和 和維護k次方的和很像,想要維護選c個數,就要把選1 c個數的方案全部維護出來 這樣當合併兩個區間的時候 pushup 只需要列舉左右區間分別取了幾個數即可 現在考慮兩種修改操作 1.區間取相反數...

bzoj2962 序列操作

有乙個長度為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的值。第一行兩個數n,q表示序列長度和操作個數。第...