간격 추가 + 간격 수정 + HDU-1698 + Horrible Queries LightOJ-1164에 대한 선분 트리의 지연 표시


HDU-1698 질문 :

n 개의 구리 스틱 행이 주어지면 초기 값은 1입니다. 이제 q 연산이 있습니다. [x, y] 간격의 스틱을 구리 스틱 (값 1),은 ​​스틱 (값 2), 황금 스틱으로 변경할 수 있습니다. (값 3). 마지막에 얻은 모든 막대기의 가치는 무엇입니까?

아이디어 :

  • 선분 트리를 사용하여 각 간격의 총 값을 저장합니다.
  • 간격 [x, y] 업데이트와 관련하여 우리는 수정해야하는 현재 간격 노드의 하위 간격 값을 나타내는 lazy 배열을 사용하여 표시합니다 (업데이트 및 쿼리에 하위 간격이 필요한 경우에만 업데이트 됨).
  • 마지막으로 각 질문에 대한 질의 질의를 사용합니다. 질의 간격이 유지 보수 간격을 완전히 포함하면 간격 합계를 직접 반환하고, 완전히 포함하지 않으면 현재 간격 노드의 하위 간격 노드를 사용하므로 아래쪽으로 업데이트는 푸시 다운 작업이 필요합니다.
  • 특정 간격을 업데이트 할 때 동일한 이유가 완전히 포함되면 직접 업데이트합니다. 그렇지 않으면 하위 간격이 사용되며 푸시 다운 후 작업을 수행해야합니다.

AC 코드는 다음과 같습니다.

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int maxn = 1e5 + 5;
int lazy[maxn << 2], ms[maxn << 2];
int n, q, x, y, z, t;

void pushup(int id){
	ms[id] = ms[id << 1] + ms[id << 1 | 1];
}

void pushdown(int id, int l, int r){
	if(lazy[id]){
		lazy[id << 1] = lazy[id << 1 | 1] = lazy[id];
		int mid = ( l + r ) >> 1;
		ms[id << 1] = (mid - l + 1) * lazy[id];
		ms[id << 1 | 1] = (r - mid) * lazy[id];
		lazy[id] = 0;
	}
}

void update(int id, int l, int r, int x, int y, int v){
	if(x <= l && r <= y){
		lazy[id] = v;
		ms[id] = (r - l + 1) * v;
		return;
	}
	pushdown(id, l, r);
	int mid = (l + r) >> 1;
	if(x <= mid){
		update(id << 1, l, mid, x, y, v);
	}
	if(y > mid){
		update(id << 1 | 1, mid + 1, r, x, y, v);
	}
	pushup(id);
}

int query(int id, int l, int r, int x, int y){
	if(x <= l && r <= y){
		return ms[id];
	}//如果不包含在内,则需要向下更新 
	pushdown(id, l, r);
	int mid = (l + r) >> 1;
	int ans = 0;
	if(x <= mid){
		ans += query(id << 1, l, mid, x, y);
	}
	if(y > mid){
		ans += query(id << 1 | 1, mid + 1, r, x, y);
	}
	return ans;
}

int main(){
	int T = 1;
	scanf("%d",&t); 
	while(t--){
		memset(lazy, 0, sizeof lazy);
		scanf("%d%d", &n, &q);
		update(1, 1, n, 1, n, 1);//将线段树整个区间置位1,即铜棒 
		for(int i = 1;i <= q;i++){
			scanf("%d%d%d", &x, &y, &z);
			update(1, 1, n, x, y, z);
		}
		printf("Case %d: The total value of the hook is %d.\n",  T++, query(1, 1, n, 1, n));
	}
	
	return 0;
}


끔찍한 질문은 LightOJ-1164를 효과에 대해 쿼리합니다.

n 길이의 배열이 주어지면 초기 값은 모두 0입니다. q 연산이 있는데, 1 xyv 연산은 구간 [x, y] 사이의 값에 v를 더하는 것을 나타내고, 0 xy 연산은 구간 [x, y]의 합계 값을 요청하여 다음에 따라 질문을 완료하는 것을 나타냅니다. 입력 및 출력.

아이디어 :

  • 간격의 합계 값을 유지하려면 선분 트리를 사용하십시오.
  • 지연 배열을 사용하여 현재 간격 노드의 하위 간격에 추가해야하는 값을 표시합니다. 하위 간격의 값을 사용해야하는 경우 푸시 다운 작업을 수행하여 하위 간격 노드의 값을 업데이트합니다. ;
  • 마지막으로 각 질문에 대한 질의 질의를 사용합니다. 질의 간격이 유지 보수 간격을 완전히 포함하면 간격 합계를 직접 반환하고, 완전히 포함하지 않으면 현재 간격 노드의 하위 간격 노드를 사용하므로 아래쪽으로 업데이트는 푸시 다운 작업이 필요합니다.
  • 특정 간격을 업데이트 할 때 동일한 이유가 완전히 포함되면 직접 업데이트합니다. 그렇지 않으면 하위 간격이 사용되며 푸시 다운 후 작업을 수행해야합니다.

AC 코드는 다음과 같습니다.

#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 1e5 + 5;
int lazy[maxn << 2];
ll ms[maxn << 2]; 
//lazy数组用于存储下标为id的区间结点中,左右儿子区间应该增加的数值 。
//lazy的作用是在有需要的时候,更新当前结点的左右儿子节点的区间和值,当不需要更新的时候就不做多余的更新 

void pushup(int id){
	ms[id] = ms[id << 1] + ms[id << 1 | 1];
}

void pushdown(int id, int l, int r){
	//父节点区间应该加上lazy的值那么子区间也应该加上同样的值,此为下方操作 
	if(lazy[id]){
		lazy[id << 1] += lazy[id]; //让左二子更新其子节点应该增加的值 
		lazy[id << 1 | 1] += lazy[id];
		int mid = (l + r) >> 1;
		ms[id << 1] += lazy[id] * (mid - l + 1);//左子树的和递增 
		ms[id << 1 | 1] += lazy[id] * (r - mid);//右子树的和递增 
		lazy[id] = 0;//增加之后清空,下一次id这个结点区间就不再增加这个值了。 
	}
}

ll query(int id, int l, int r, int x, int y){
	if(x <= l && r <= y){
		return ms[id];
	}
	pushdown(id, l, r);
	//所查询的区间不完全覆盖所维护的区间,所以将所维护的区间向下推,使得当前结点的子节点区间按照因该加上的值更新。 
	int  mid = (l + r) >> 1;
	ll ans = 0;
	if(x <= mid){
		ans += query(id << 1, l, mid, x, y);
	}
	if(y > mid){
		ans += query(id << 1 | 1,mid + 1, r, x, y);
	}
	return ans;
} 

void update(int id, int l, int r, int x, int y, int v){
	if(x <= l && r <= y){
		ms[id] += (r - l + 1) * v;
		lazy[id] += v;
	}else{
		pushdown(id , l, r);//说明当前区间不再查询区间之内,因此要递归到下一层区间结点。
		//所以之前存在于lazy数组中还没有更新的值此时需要被更新。
		int mid = (l + r) >> 1;
		if(x <= mid){
			update(id << 1, l, mid, x, y, v);
		} 
		if(y > mid){
			update(id << 1 | 1, mid + 1, r, x, y, v);
		}
		pushup(id);//向上合并。 
	}
} 

int t, n, m, op, x, y, d;
int main() {
	int cnt = 1;
	scanf("%d", &t);
	while (t--) {
		memset(lazy, 0, sizeof(lazy));
		memset(ms, 0, sizeof(ms));
		printf("Case %d:\n", cnt++);
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= m; i++) {
			scanf("%d%d%d", &op, &x, &y);
			x++, y++;
			if (op == 0) {
				scanf("%d", &d); 
				update(1, 1, n, x, y, d);
			} else {
				printf("%lld\n", query(1, 1, n, x, y));
			}
		}
	} 
	return 0;
} 

 

추천

출처blog.csdn.net/qq_40596572/article/details/104014303