线段树原理:把区间一分为二,去找到想要的,在查询范围的区间。 //建议去看一下线段树的基本博客 线段树的真正作用不是单纯数值,而是很好的利用区间信息 add:运用lasy_tag。记录加的数目而不直接进行更新,而在区间信息里记录。 set:运用lasy_tag。通过标记记录set值,注意遇到set的大区间直接退回。 注意在询问的时候利用好这两个信息。 (maintain)维护操作: 1.遇到标准区间进行标准更新; 2.遇到set,add在任意区间都赶快修改 (pushdown)下传操作: 1.在set操作时清楚add 2.在add操作时直接传 (update) 直接改标记,注意把改set时清楚add (query) 询问: 1.遇到set的区间,停止询问, 把有(只要占了一个点,见下文的min()-max()+1)查询区间内的那一段返回 2.遇到查询内的区间,考虑下穿过来的add,标记//本次操作使用了多颗线段树。树套树更快?等着你! //本次操作采用刘汝佳的代码风格,确实有工程性和可读性 //这次操作可用了add,set,sum #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #define MM 1<<17 #define rep(i,a,b) for(int i=a; i<=b; ++i) using namespace std; int lson(int h) { return h<<1; } int rson(int h) { return (h<<1)|1;} int half(int h) { return h>>1; } int x1, x2, y1, y2, ord , v, _sum , _max, _min; int r,c,m; struct Segment_tree { int addv[MM], setv[MM], minv[MM], maxv[MM], sumv[MM]; void maintain(int h,int L,int R) { int l = lson(h), r = rson(h); if(L<R) { sumv[h] = sumv[l] + sumv[r]; maxv[h] = max(maxv[l], maxv[r]); minv[h] = min(minv[l], minv[r]); } if(setv[h] >=0) { minv[h] = maxv[h] = setv[h]; sumv[h] = (R-L+1) * setv[h]; } if(addv[h]) { minv[h] += addv[h]; maxv[h] += addv[h]; sumv[h] += (R-L+1) * addv[h]; } } void pushdown(int h) { int l = lson(h), r = rson(h); if(setv[h] >= 0) { setv[l] = setv[r] = setv[h]; addv[l] = addv[r] = 0; setv[h] = -1; } if(addv[h]) { addv[l] += addv[h]; addv[r] += addv[h]; addv[h] = 0; } } void update(int h,int L,int R) { int l = lson(h), r = rson(h); if(y1 <= L && R <= y2) { if (ord == 2) { setv[h] = v; addv[h] = 0; } else addv[h] += v; } else { pushdown(h); int M = half(L+R); if(y1 <= M) update(l,L,M); else maintain(l,L,M); if(M < y2) update(r,M+1,R); else maintain(r,M+1,R); } maintain(h,L,R); } void query(int h,int L,int R,int add) { if(setv[h] >= 0) { int k = addv[h] + setv[h] + add; _max = max(_max, k); _min = min(_min, k); _sum += k * (min(R,y2)-max(L,y1)+1); } else if(y1 <= L && R <= y2) { _max = max(_max, add + maxv[h]); _min = min(_min, add + minv[h]); _sum += sumv[h] + add * (R-L+1); } else { int l = lson(h) , r = rson(h); int M = half(L+R); if(y1 <= M) query(l,L,M,add+addv[h]); if(M < y2) query(r,M+1,R,add+addv[h]); } } }; struct Segment_tree solver[25]; const int INF = 0x3f3f3f3f; int main() { while(scanf("%d%d%d",&r,&c,&m)!=EOF) { memset(solver,0,sizeof(solver)); rep(i,0,r) {memset(solver[i].setv, -1, sizeof(solver[i].setv)); solver[i].setv[1] = 0;} while(m--) { scanf("%d%d%d%d%d",&ord,&x1,&y1,&x2,&y2); if(ord < 3) { scanf("%d",&v); rep(i,x1,x2) solver[i].update(1,1,c); } else { _max = -INF , _min = INF, _sum = 0; rep(i,x1,x2) solver[i].query(1,1,c,0); printf("%d %d %d\n",_sum, _min, _max); } } } }
线段树区间修改
最新推荐文章于 2024-03-27 21:13:35 发布