Marque paresseuse de l'arborescence des segments de ligne pour l'ajout d'intervalle + modification de l'intervalle + HDU-1698 + Requêtes horribles LightOJ-1164


Question HDU-1698 à l'effet:

Étant donné une rangée de n bâtons de cuivre, leur valeur initiale est 1. Maintenant, il y a q opérations, vous pouvez changer les bâtons dans l'intervalle [x, y] en bâtons de cuivre (valeur 1), bâtons d'argent (valeur 2), bâtonnet d'or (valeur de 3). Quelle est la valeur de tous les bâtons obtenus à la fin?

Idées:

  • Utilisez l'arborescence des segments de ligne pour enregistrer la valeur totale de chaque intervalle.
  • En ce qui concerne la mise à jour de l'intervalle [x, y], nous utilisons le tableau paresseux pour marquer, qui représente la valeur du sous-intervalle du nœud d'intervalle actuel qui doit être modifié (mis à jour uniquement lorsque le sous-intervalle est nécessaire pour la mise à jour et la requête)
  • Enfin, utilisez la requête de requête pour chaque question. Si l'intervalle de requête couvre complètement l'intervalle de maintenance, la somme des intervalles est directement renvoyée; si elle n'est pas complètement couverte, le nœud de sous-intervalle du nœud d'intervalle actuel sera utilisé, donc vers le bas la mise à jour est une opération pushdown requise
  • Lors de la mise à jour d'un certain intervalle, la même raison, s'il est complètement couvert, mise à jour directement; sinon, le sous-intervalle sera utilisé, et l'opération doit être effectuée après le refoulement.

Le code AC est le suivant:

#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;
}


Question Horrible Queries LightOJ-1164 à l'effet:

Étant donné un tableau de longueur n, sa valeur initiale est entièrement égale à 0. Il y a q opérations, dont l'opération 1 xyv représente l'ajout de v à la valeur entre l'intervalle [x, y]; et l'opération 0 xy représente la demande de la valeur de somme dans l'intervalle [x, y] pour compléter la question selon l'entrée et la sortie.

Idées:

  • Utilisez une arborescence de segments de ligne pour conserver la valeur de somme dans l'intervalle;
  • Utilisez le tableau différé pour marquer la valeur à ajouter au sous-intervalle du nœud d'intervalle actuel. Lorsque la valeur du sous-intervalle doit être utilisée, effectuez une opération de refoulement pour mettre à jour la valeur du nœud de sous-intervalle ;
  • Enfin, utilisez la requête de requête pour chaque question. Si l'intervalle de requête couvre complètement l'intervalle de maintenance, la somme des intervalles est directement renvoyée; si elle n'est pas complètement couverte, le nœud de sous-intervalle du nœud d'intervalle actuel sera utilisé, donc vers le bas la mise à jour est une opération pushdown requise
  • Lors de la mise à jour d'un certain intervalle, la même raison, s'il est complètement couvert, mise à jour directement; sinon, le sous-intervalle sera utilisé, et l'opération doit être effectuée après le refoulement.

Le code AC est le suivant:

#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;
} 

 

Je suppose que tu aimes

Origine blog.csdn.net/qq_40596572/article/details/104014303
conseillé
Classement