|
題目鏈接: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;
}
|