程序员人生 网站导航

BZOJ 1798 Ahoi 2009 维护序列seq

栏目:php开源时间:2014-09-30 03:41:45

题目大意:维护一个序列,能够区间加,区间乘,然后取区间和模一个数的值。


思路:线段树维护一个有两个域的标记,一个表示加,一个表示乘。下传的时候一起下传,先乘后加。


CODE:


#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define MO p #define LEFT (pos << 1) #define RIGHT (pos << 1|1) #define CNT (r - l + 1) using namespace std; long long p; struct Mark{ long long p_mark,m_mark; Mark() { m_mark = 1; p_mark = 0; } void operator +=(long long c) { p_mark = (p_mark + c) % MO; } void operator *=(long long c) { p_mark = (p_mark * c) % MO; m_mark = (m_mark * c) % MO; } void operator +=(const Mark &a) { m_mark = (m_mark * a.m_mark) % MO; p_mark = (p_mark * a.m_mark + a.p_mark) % MO; } }; struct Complex{ long long sum; Mark mark; }tree[MAX << 2]; int cnt,asks; long long src[MAX]; void BuildTree(int l,int r,int pos); void Mulitiply(int l,int r,int x,int y,int pos,long long c); void Plus(int l,int r,int x,int y,int pos,long long c); int Ask(int l,int r,int x,int y,int pos); inline void PushDown(int pos,int cnt); int main() { cin >> cnt >> p; for(int i = 1;i <= cnt; ++i) scanf("%lld",&src[i]); BuildTree(1,cnt,1); cin >> asks; for(int flag,i = 1;i <= asks; ++i) { scanf("%d",&flag); int x,y,z; switch(flag) { case 1: scanf("%d%d%d",&x,&y,&z); Mulitiply(1,cnt,x,y,1,z); break; case 2: scanf("%d%d%d",&x,&y,&z); Plus(1,cnt,x,y,1,z); break; case 3: scanf("%d%d",&x,&y); printf("%d ",(int)Ask(1,cnt,x,y,1)); break; } } return 0; } void BuildTree(int l,int r,int pos) { tree[pos].mark.p_mark = 0; tree[pos].mark.m_mark = 1; if(l == r) { tree[pos].sum = src[l] % MO; return ; } int mid = (l + r) >> 1; BuildTree(l,mid,LEFT); BuildTree(mid + 1,r,RIGHT); tree[pos].sum = (tree[LEFT].sum + tree[RIGHT].sum) % MO; } void Mulitiply(int l,int r,int x,int y,int pos,long long c) { if(l == x && y == r) { tree[pos].sum = (tree[pos].sum * c) % MO; tree[pos].mark *= c; return ; } PushDown(pos,CNT); int mid = (l + r) >> 1; if(y <= mid) Mulitiply(l,mid,x,y,LEFT,c); else if(x > mid) Mulitiply(mid + 1,r,x,y,RIGHT,c); else { Mulitiply(l,mid,x,mid,LEFT,c); Mulitiply(mid + 1,r,mid + 1,y,RIGHT,c); } tree[pos].sum = (tree[LEFT].sum + tree[RIGHT].sum) % MO; } void Plus(int l,int r,int x,int y,int pos,long long c) { if(l == x && y == r) { tree[pos].sum = (tree[pos].sum + (c * CNT) % MO) % MO; tree[pos].mark += c; return ; } PushDown(pos,CNT); int mid = (l + r) >> 1; if(y <= mid) Plus(l,mid,x,y,LEFT,c); else if(x > mid) Plus(mid + 1,r,x,y,RIGHT,c); else { Plus(l,mid,x,mid,LEFT,c); Plus(mid + 1,r,mid + 1,y,RIGHT,c); } tree[pos].sum = (tree[LEFT].sum + tree[RIGHT].sum) % MO; } int Ask(int l,int r,int x,int y,int pos) { if(l == x && y == r) return tree[pos].sum; PushDown(pos,CNT); int mid = (l + r) >> 1; if(y <= mid) return Ask(l,mid,x,y,LEFT); if(x > mid) return Ask(mid + 1,r,x,y,RIGHT); int left = Ask(l,mid,x,mid,LEFT); int right = Ask(mid + 1,r,mid + 1,y,RIGHT); return (left + right) % MO; } inline void PushDown(int pos,int cnt) { if(tree[pos].mark.m_mark == 1 && !tree[pos].mark.p_mark) return ; tree[LEFT].mark += tree[pos].mark; tree[RIGHT].mark += tree[pos].mark; if(tree[pos].mark.m_mark != 1) { tree[LEFT].sum = (tree[LEFT].sum * tree[pos].mark.m_mark) % MO; tree[RIGHT].sum = (tree[RIGHT].sum * tree[pos].mark.m_mark) % MO; tree[pos].mark.m_mark = 1; } if(tree[pos].mark.p_mark) { tree[LEFT].sum = (tree[LEFT].sum + ((cnt - (cnt >> 1)) * tree[pos].mark.p_mark) % MO) % MO; tree[RIGHT].sum = (tree[RIGHT].sum + ((cnt >> 1) * tree[pos].mark.p_mark) % MO) % MO; tree[pos].mark.p_mark = 0; } }

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐