Forças de código educacional rodada 54 (avaliado para a divisão 2) E. Vasya e uma árvore (树上 差分)

E. Vasya e uma árvore

limite de tempo por teste

2 segundos

limite de memória por teste

256 megabytes

entrada

entrada padrão

resultado

saída padrão

Vasya tem uma árvore consistindo de nn vértices com raiz no vértice 11. A princípio, todos os vértices têm 00 escrito nele.

Seja d (i, j) d (i, j) a distância entre os vértices ii e jj, ou seja, o número de arestas no caminho mais curto de ii a jj. Além disso, vamos denotar kk-subárvore do vértice xx - conjunto de vértices yy de modo que as próximas duas condições sejam atendidas:

  • xx é o ancestral de yy (cada vértice é o ancestral de si mesmo);
  • d (x, y) ≤kd (x, y) ≤k.

Vasya precisa de você para processar consultas mm. A segunda consulta é um vivi, didi e xixi triplo. Para cada consulta, Vasya adiciona o valor xixi a cada vértice da didi-subárvore de vivi.

Relate ao Vasya todos os valores, escritos nos vértices da árvore após o processamento de todas as consultas.

Entrada

A primeira linha contém um único inteiro nn (1≤n≤3⋅1051≤n≤3⋅105) - número de vértices na árvore.

Cada uma das próximas n − 1n − 1 linhas contém dois inteiros xx e yy (1≤x, y≤n1≤x, y≤n) - aresta entre os vértices xx e yy. É garantido que determinado gráfico é uma árvore.

A próxima linha contém um único inteiro mm (1≤m≤3⋅1051≤m≤3⋅105) - número de consultas.

Cada uma das próximas linhas mm contém três inteiros vivi, didi, xixi (1≤vi≤n1≤vi≤n, 0≤di≤1090≤di≤109, 1≤xi≤1091≤xi≤109) - descrição do ii- ª consulta.

Resultado

Imprime nn inteiros. O ii-ésimo inteiros é o valor, escrito no ii-ésimo vértice depois de processar todas as consultas.

Exemplos

entrada

cópia de

5
1 2
1 3
2 4
2 5
3
1 1 1
2 0 10
4 10 100

resultado

cópia de

1 11 1 100 0 

entrada

cópia de

5
2 3
2 1
5 4
3 4
5
2 0 4
3 10 1
1 2 3
2 3 10
1 1 7

resultado

cópia de

10 24 14 11 11 

Nota

No primeiro exemplo, os valores iniciais nos vértices são 0,0,0,0,00,0,0,0,0. Após a primeira consulta os valores serão iguais a 1,1,1,0,01,1,1,0,0. Após a segunda consulta os valores serão iguais a 1,11,1,0,01,11,1,0,0. Após a terceira consulta, os valores serão iguais a 1,11,1,100,01,11,1,100,0.

Ideia principal:

    Uma árvore com uma raiz de 1, operações Q, cada ponto de tempo xe o peso do ponto dentro de uma certa distância do ponto x são adicionados com W e, finalmente, os pesos dos pontos de todos os pontos são produzidos de uma vez.

solução:

    Se você modificar a resposta de saída final várias vezes, poderá considerar o método de diferença primeiro.

    Primeiro, coloque a consulta off-line, salve a operação correspondente para cada ponto e adicione o peso W ao ponto x atual. No final do DFS, cada vez que ele entra em uma camada, o peso de profundidade correspondente que precisa ser subtraído é atualizado e a subárvore é percorrida. Adicione novamente mais tarde.

Código aceito

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 3e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

vector <pir> ask[N];
vector <int> G[N];
int dep[N], n, q;
ll ans[N], s[N];

void DFS(int x, int fa, int dep) {
	for (auto it : ask[x]) {     // 先做减法
		int d = it.first, w = it.second;
		s[min(N - 1, dep + d + 1)] -= w;
	}
	ans[x] += s[dep];   // 差分
	for (auto v : G[x]) {
		if (v != fa)
			ans[v] += ans[x], DFS(v, x, dep + 1);
	}
	for (auto it : ask[x]) {   // 再做加法
		int d = it.first, w = it.second;
		s[min(N - 1, dep + d + 1)] += w;
	}
}

int main()
{
#ifdef OlaMins
	freopen("D:/input.txt", "r", stdin);
	//freopen("D:/output.txt", "w", stdout);
#endif

	cin >> n;
	for (int i = 1; i < n; i++) {
		int u, v;
		sc("%d %d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	cin >> q;
	while (q--) {
		int x, k, w;
		sc("%d %d %d", &x, &k, &w);  // 询问离线
		ans[x] += w;
		ask[x].push_back({ k, w });
	}
	DFS(1, 0, 0);

	for (int i = 1; i <= n; i++)
		printf("%lld%c", ans[i], " \n"[i == n]);
	return 0;
}

 

Acho que você gosta

Origin blog.csdn.net/weixin_43851525/article/details/110500560
Recomendado
Clasificación