ZJU 2706 Thermal Death of the Universe
題目鏈接: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;
}posted on 2011-03-30 11:58 英雄哪里出來 閱讀(1240) 評論(2) 編輯 收藏 引用 所屬分類: 線段樹

