Educational Codeforces Round 54(Div。2の評価)E。Vasyaand a Tree(树上鉛筆)

E.ヴァシャと木

テストごとの制限時間

2秒

テストごとのメモリ制限

256メガバイト

入力

標準入力

出力

標準出力

Vasyaには、頂点11にルートを持つnn個の頂点で構成されるツリーがあります。最初は、すべての頂点に00が書き込まれています。

d(i、j)d(i、j)を頂点iiとjjの間の距離、つまりiiからjjへの最短経路のエッジの数とします。また、次の2つの条件が満たされるように、頂点xxのkkサブツリー—頂点yyのセットを示しましょう。

  • xxはyyの祖先です(各頂点はそれ自体の祖先です)。
  • d(x、y)≤kd(x、y)≤k。

Vasyaでは、mmクエリを処理する必要があります。2番目のクエリは、トリプルvivi、didi、およびxixiです。クエリごとに、Vasyaはviviのdidiサブツリーから各頂点に値xixiを追加します。

すべてのクエリを処理した後、ツリーの頂点に書き込まれたすべての値をVasyaに報告します。

入力

最初の行には、単一の整数nn(1≤n≤3⋅1051≤n≤3⋅105)—ツリー内の頂点の数が含まれています。

次のn-1n-1行のそれぞれには、2つの整数xxとyy(1≤x、y≤n1≤x、y≤n)—頂点xxとyyの間のエッジが含まれます。与えられたグラフがツリーであることが保証されます。

次の行には、単一の整数mm(1≤m≤3⋅1051≤m≤3⋅105)—クエリの数が含まれています。

次のmm行のそれぞれには、3つの整数vivi、didi、xixi(1≤vi≤n1≤vi≤n、0≤di≤1090≤di≤109、1≤xi≤1091≤xi≤109)が含まれています—ii-の説明クエリ。

出力

nn個の整数を出力します。ii番目の整数は、すべてのクエリを処理した後にii番目の頂点に書き込まれる値です。

入力

コピー

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

出力

コピー

1 11 1 100 0 

入力

コピー

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

出力

コピー

10 24 14 11 11 

注意

最初の例では、頂点の初期値は0,0,0,0,00,0,0,0,0です。最初のクエリの後、値は1,1,1,0,01,1,1,0,0に等しくなります。2番目のクエリの後、値は1,11,1,0,01,11,1,0,0に等しくなります。3番目のクエリの後、値は1,11,1,100,01,11,1,100,0に等しくなります。

本旨:

    ルートが1、Q演算、各時点x、およびポイントxから一定の距離内にあるポイントの重みを持つツリーにWが加算され、最後にすべてのポイントのポイントの重みが一度に出力されます。

解決:

    最終的な出力回答を数回変更する場合は、最初に差分方法を検討できます。

    まず、クエリをオフラインにし、各ポイントに対応する操作を保存して、現在のポイントxに重みWを追加します。DFSの最後で、レイヤーに入るたびに、減算する必要のある対応する深度の重みが更新され、サブツリーがトラバースされます。後で追加し直します。

受け入れられたコード

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

 

おすすめ

転載: blog.csdn.net/weixin_43851525/article/details/110500560