|
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2706
/**//* 题意: 给定一个长度为N(N <= 30000)的数列Si,紧接着Q条区间处理,每一条处理的要 求是将给定的区间内的数字替换成他们的平均值,替换时如果当前数列的总和比原先 数列的总和小或者相等时,平均值向上取整,否则向下取整,最后要求输出处理完的 数组的每一个元素。
解法: 线段树
思路: 一看到数据量就可以首先确定是线段树了,然后我们来把这题需要求的东西分解 一下,题目中提到当前数列和和原数列和比较大小,所以首先一个操作就是区间求和 ,然后将区间内的数替换成另外一个数,这就用到了区间修改,和线段树的操作完全 吻合。接下来就可以开始设计线段树结点的域了。其实这题的思想和pku 3468是大同 小异的,还是lazy思想。每次插入的时候不更新到叶子结点,在插入区间完全覆盖当 前区间时就返回,否则将当前结点的lazy标记传递给左右儿子,并且更新左右儿子的 sum值,注意,这里每次不是累加,因为是修改,所以直接将 sum*左右儿子的区间长 度 分别赋值给左右儿子即可。递归结束时更新当前结点的sum值。询问时也是相同, 每次传递lazy标记给儿子。这样就可以做到询问和插入都是log(n)。 */
#include <iostream> #include <cstdio> #include <cstring> using namespace std;
#define maxn 30010 #define inf INT_MIN #define ll long long
struct Tree { int p, l, r; ll sum; ll lazy_tag;
void ClearTag();
int GetMid() { return (l + r) >> 1; } int GetLen() { return r - l + 1; } }T[4*maxn];
void Tree::ClearTag() { if(lazy_tag) { T[p<<1].lazy_tag = lazy_tag; T[p<<1|1].lazy_tag = lazy_tag; T[p<<1].sum = lazy_tag * T[p<<1].GetLen(); T[p<<1|1].sum = lazy_tag * T[p<<1|1].GetLen(); lazy_tag = 0; } }
int n, m; int val[maxn];
void Build(int p, int l, int r) { T[p].l = l; T[p].r = r; T[p].p = p; T[p].lazy_tag = 0;
if(l == r) { T[p].sum = val[l]; return ; }
int mid = (l + r) >> 1; Build(p<<1, l, mid); Build(p<<1|1, mid+1, r); T[p].sum = T[p<<1].sum + T[p<<1|1].sum; }
ll Query(int p, int l, int r) { if(l <= T[p].l && T[p].r <= r) { return T[p].sum; } T[p].ClearTag(); int mid = T[p].GetMid();
ll v = 0; if(l <= mid) { v += Query(p<<1, l, r); } if(r >= mid + 1) { v += Query(p<<1|1, l, r); }
return v; }
void Modify(int p, int l, int r, ll val) { if(l <= T[p].l && T[p].r <= r) { T[p].lazy_tag = val; T[p].sum = val * T[p].GetLen(); return ; } T[p].ClearTag(); int mid = T[p].GetMid(); if(l <= mid) { Modify(p<<1, l, r, val); } if(r >= mid + 1) { Modify(p<<1|1, l, r, val); }
T[p].sum = T[p<<1].sum + T[p<<1|1].sum; }
ll Calc(ll val, int dn, bool bRoundUp) { if(val >= 0) { if(bRoundUp) { return (val + dn - 1) / dn; }else return val / dn; }else { val = -val; if(bRoundUp) { return -(val / dn); }else { return -((val + dn - 1) / dn); } } }
int main() { int i; int x, y; while(scanf("%d %d", &n, &m) != EOF) { for(i = 1; i <= n; i++) { scanf("%d", &val[i]); } Build(1, 1, n); ll ans = T[1].sum; while(m--) { scanf("%d %d", &x, &y); ll Sum = Query(1, x, y); ll all = Query(1, 1, n); Sum = Calc(Sum, y-x+1, all <= ans); Modify(1, x, y, Sum); } for(i = 1; i <= n; i++) { if(i != 1) printf(" "); printf("%lld", Query(1, i, i)); } puts("\n"); } return 0; }
|