標籤: 線段樹
題目鏈結
給你一串串行,要你維護三個操作:
1.區間加法
2.區間取相反數
3.區間內任意選k個數相乘的積
第三個操作看起來一臉懵逼啊。
其實是可以合併的。
$ c[o].s[i]=\sum_^c[lc].s[j]×c[rc].s[i-j]\(
跟\)c_mn=\sum_n c_ni×c_ $這個等式是乙個道理的吧。
然後想怎麼維護加和取反。
取反比較容易,把取奇數個的答案變成相反數。
加法就稍微複雜一點。
假如p是加上的數,s[i]是區間內取k個數的答案。
\[s[i]=\sum_^k c_^i×s[j]×p^
\](不知道為什麼常數很大,bzoj上43s才過)
#include#include#include#include#include#include#include#include#include#includeusing namespace std;
#define ll long long
#define rep(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define drep(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define erep(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
const int mod=19940417;
const int maxn=1e5+20;
struct node
}};node c[maxn*4];
int n;
int a[maxn],c[maxn][25];
#define lc (o<<1)
#define rc (o<<1 | 1)
#define left lc,l,mid
#define right rc,mid+1,r
void reverse(int o,int l,int r)
void add(int o,int l,int r,ll add) }}
void pushdown(int o,int l,int r)
if(c[o].add) }
void make_tree(int o,int l,int r)
int mid=(l+r)>>1;
make_tree(left);
make_tree(right);
c[o].merge(c[lc],c[rc]);
}int q;
void init()
make_tree(1,1,n);
}void updatea(int ql,int qr,ll x,int o,int l,int r)
int mid=(l+r)>>1;
pushdown(o,l,r);
if(ql<=mid )updatea(ql,qr,x,left);
if(qr>mid)updatea(ql,qr,x,right);
c[o].merge(c[lc],c[rc]);
}void updater(int ql,int qr,int o,int l,int r)
int mid=(l+r)>>1;
pushdown(o,l,r);
if(ql<=mid)updater(ql,qr,left);
if(qr>mid)updater(ql,qr,right);
c[o].merge(c[lc],c[rc]);
}node query(int ql,int qr,int o,int l,int r)
}void doing()
else if(ch=='r')
else
}}int main()
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表示序列長度和操作個數。第...
bzoj 2962 序列操作
time limit 50 sec memory limit 256 mb submit status discuss 有乙個長度為n的序列,有三個操作1.i a b c表示將 a,b 這一段區間的元素集體增加c,2.r a b表示將 a,b 區間內所有元素變成相反數,3.q a b c表示詢問 a...