luoguP3359 改造异或树

https://www.luogu.org/problemnew/show/P3359

因为 a ^ b ^ b = a,所以我们预处理 1 到所有点的距离,将删边的操作反过来变成加边,对于每一个联通块用 map 维护 1 到联通块中的点异或值为 x 的数的个数,乘法原理统计答案,加边时启发式合并即可

#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
typedef long long ll;

template <typename T>
inline void read(T &f) {
	f = 0; T fu = 1; char c = getchar();
	while(c < '0' || c > '9') {if(c == '-') fu = -1; c = getchar();}
	while(c >= '0' && c <= '9') {f = (f << 3) + (f << 1) + (c & 15); c = getchar();}
	f *= fu;
}

const int N = 1e5 + 5;

struct Edge {
	int u, v, next, val;
}G[N << 1];

map <int, int> t[N];
ll Ans[N], ans;
int d[N], f[N], del[N], x[N], y[N], z[N], head[N];
int n, tot;

inline void addedge(int u, int v, int val) {
	G[++tot] = (Edge) {u, v, head[u], val}, head[u] = tot;
	G[++tot] = (Edge) {v, u, head[v], val}, head[v] = tot;
}

int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);}

void dfs(int u, int fa) {
	for(int i = head[u]; i; i = G[i].next) {
		int v = G[i].v;
		if(v == fa) continue;
		d[v] = d[u] ^ G[i].val;
		dfs(v, u);
	}
}

int main() {
	cin >> n;
	for(int i = 1; i < n; i++) {
		read(x[i]); read(y[i]); read(z[i]);
		addedge(x[i], y[i], z[i]);
	}
	for(int i = 1; i < n; i++) read(del[i]);
	for(int i = 1; i <= n; i++) f[i] = i;
	dfs(1, 0); for(int i = 1; i <= n; i++) t[i][d[i]] = 1;
	for(int i = n - 1; i >= 1; i--) {
		int l = x[del[i]], r = y[del[i]];
		int x = find(l), y = find(r);
		if(t[x].size() > t[y].size()) swap(x, y);
		for(map <int, int> :: iterator it = t[x].begin(); it != t[x].end(); it++) {
			ans += (ll)it -> second * (ll)t[y][it -> first];
			t[y][it -> first] += it -> second;
		}
		f[x] = y; Ans[i] = ans; t[x].clear();
	}
	for(int i = 1; i <= n; i++) printf("%lld\n", Ans[i]);
	return 0;
}
posted @ 2018-09-19 21:16  LJC00118  阅读(158)  评论(0编辑  收藏  举报
/*
*/