題目大意:給定乙個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表示序列長度和操作個數。第...