首页 > 代码库 > zoj 2706 Thermal Death of the Universe (线段树区间更新,区间求和)
zoj 2706 Thermal Death of the Universe (线段树区间更新,区间求和)
/* 题意:给n个数,m个操作,每次把区间[l,r]的数用它们的平均值替代, 如果平均值不是整数,且当前n个数的和小于原先的和就向上round,不然就向下round; */ #include <cstdio> # include <algorithm> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 ///lson和rson分别表示结点的左儿子和右儿子 ///rt表示当前子树的根(root),也就是当前所在的结点 const int maxn =30010; ///maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍 long long sum[maxn<<2];///求和 long long col[maxn<<2];///用来标记每个节点,为0则表示没有标记,否则为标记 long long str[maxn]; void PushUP(long long rt)///PushUP(int rt)是把当前结点的信息更新到父结点 { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void PushDown(long long rt,long long m)///pushDown(int rt)是把当前结点的信息更新给儿子结点,m为分区间的长度 { ///对某一个区间进行改变,如果被标记了,在查询的时候就得把改变传给子节点,因为查询的并不一定是当前区间 if (col[rt])///被标记过,说明区间改变了 { col[rt<<1] = col[rt<<1|1] = col[rt]; /*此处用add[rt]乘以区间长度,不是add[rt<<1], 因为rt的儿子节点如果被多次标记,之前被标记时, 就已经对sum[rt<<1]更新过了。 */ sum[rt<<1] = (m - (m >> 1)) * col[rt];///更新左儿子的和 sum[rt<<1|1] = (m >> 1) * col[rt];///更新右儿子的和 col[rt] = 0;///将标记向儿子节点移动后,父节点的延迟标记去掉 ///传递后,当前节点标记域清空 } } void build(long long l,long long r,long long rt)///建树 { col[rt] = 0; if (l == r) { scanf("%lld",&sum[rt]); return ; } long long m = (l + r) >> 1; build(lson); build(rson); PushUP(rt); } void update(long long L,long long R,long long c,long long l,long long r,long long rt)///区间更新 { if (L <= l && r <= R) { col[rt] = c; sum[rt] = c * (r - l + 1); return ; } /*当要对被延迟标记过的这段区间的儿子节点进行更新时,先要将延迟标记向儿子节点移动 当然,如果一直没有对该段的儿子节点更新,延迟标记就不需要向儿子节点移动,这样就使 更新操作的时间复杂度仍为O(logn),也是使用延迟标记的原因。 */ PushDown(rt , r - l + 1);///延迟标志域向下传递 long long m = (l + r) >> 1; if (L <= m) update(L , R , c , lson); if (R > m) update(L , R , c , rson); PushUP(rt);///向上传递更新和 } long long query(long long L,long long R,long long l,long long r,long long rt)///区间求和 { if (L <= l && r <= R) { return sum[rt]; } PushDown(rt , r - l + 1);///要取rt子节点的值时,也要先把rt的延迟标记向下移动 long long m = (l + r) >> 1; long long ret = 0; if (L <= m) ret += query(L , R , lson); if (m < R) ret += query(L , R , rson); return ret; } int main() { long long t,n,i; long long a,b; long double ave; long long sum,sum1; while(~scanf("%lld%lld",&n,&t)) { build(1 , n , 1); sum=query(1,n,1,n,1); while(t--) { scanf("%lld%lld",&a,&b); sum1=query(a,b,1,n,1); ave=sum1*1.0/(b-a+1.0); if(ave==(long long)ave) ave=(long long)ave; else///注意负数的进舍 { sum1=query(1,n,1,n,1); if(sum1<=sum) { if(ave>0) ave=(long long)ave+1; else ave=(long long)ave; } else { if(ave>0) ave=(long long )ave; else ave=(long long)ave-1; } } update(a,b,(long long)ave,1,n,1); } for(i=1; i<=n; i++) { if(i==n) printf("%lld\n",query(i,i,1,n,1)); else printf("%lld ",query(i,i,1,n,1)); } printf("\n"); } return 0; }
zoj 2706 Thermal Death of the Universe (线段树区间更新,区间求和)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。