Luogu P3359 Transformation XOR Tree

Topic description

Given a tree of n points, each edge has a weight. Now delete all n-1 edges in order, and ask how many paths are currently satisfied for each edge that is deleted so that the XOR sum of all edge weights on the path is 0.

Input and output format

Input format:

 

The first line contains an integer n.

Next n-1 lines, each line contains three integers ai, bi, zi, satisfying 1<= ai, bi <=n, indicating that there is a weight between the point numbered ai and the point numbered bi on the tree. side of zi.

The next line of n-1 integers, separated by a space, represents an arrangement of 1~n-1, which represents the order of edge deletion of n-1 edges.

 

Output format:

 

Output n lines, each line is an integer, which in turn represents the number of paths with the edge weight XOR and zero after the 0~n - 1th edge is deleted.

 

Input and output example

Input example #1: 
4
1 2 0
2 3 0
2 4 0
3 1 2
Sample output #1: 
6
3
1
0

illustrate

For 20% of the data, n <= 1000.

For the other 30% of the data, all zi = 0 are satisfied.

For all data, n <= 10^5, 0 <= zi <= 10^9.

 

 

    It would be nice to have more high-quality original questions like this on Luogu qwq (Tucao)

 

    First of all, don't consider the mess of deleting edges. If you are given a tree, you are asked how many paths Xor sum between points is zero. How to find it? ? ?

    "I know I know, it's not just point and divide, the one that passes through the current center of gravity can be calculated in O (subtree size) (the Xor sum of the two endpoints to the root is the same as a pair), and the one that does not pass can be found recursively, It's ojbk without sorting O(N log N)!"

    "Sorry, in fact, dfs once is enough..."

    Due to the extremely special nature of Xor (Xor is equivalent to doing nothing on both sides of a number), we can directly select a root and then count the same point logarithm of Xor[] (the path to the root XOR sum) once dfs Well, because the paths above the LCA are XORed twice, which is equivalent to no XOR. . .

 

    With this relatively simple algorithm, we are very good at dealing with dynamic situations.

    As we all know, adding an edge is easier than deleting an edge, so we can do the opposite, considering how many new point-to-path Xor sums will be generated by adding an edge to 0.

 

    Of course, it takes a bit of brains to get here: we use the union lookup to maintain the root of the tree where each point is currently, and hang an unordered_map on the root of the tree to record the Xor[] ( Of course, you only need to remember how many is there are for Xor[i] = x for any x). When merging, because the tree roots of the two connected components are different, it is necessary to violently recalculate the Xor[] of the small tree (based on the root of the big tree), and clear the unordered_map of the small tree, and then calculate the new The Xor[] is added to the unordered_map of the root of the big tree, and finally it is the merge of the merged set. Don't forget to add an edge to the graph. . . Otherwise, there will be no dfs 233 in the future.

    But it looks so violent? Will it time out? ? ?

    But this is a heuristic merge, a tree of size siz will contribute a siz to the time complexity of the merge if and only if it is merged with a tree of size > siz, resulting in a new tree of size > 2*siz , so a point contributes at most log N times of merging complexity to the big tree, so the total complexity is O(N log N).

 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define pb push_back
const int maxn=100005;
unordered_map<int,int> mmp[maxn];
int n,m,Fa[maxn],p[maxn],u[maxn],v[maxn],w[maxn],S[maxn],T,tp;
int to[maxn*2],ne[maxn*2],hd[maxn],num,siz[maxn],Xor[maxn],val[maxn*2];
inline void add(int x,int y,int z){ to[++num]=y,ne[num]=hd[x],hd[x]=num,val[num]=z;}
int getFa(int x){ return Fa[x]==x?x:(Fa[x]=getFa(Fa[x]));}
ll ans[maxn],now;

void dfs(int x,int fa){
	S[++tp]=Xor[x],now+=(ll)mmp[T][Xor[x]];
	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa) Xor[to[i]]=Xor[x]^val[i],dfs(to[i],x);
}

inline void Merge(int x,int y,int z){
	int fa=getFa(x),fb=getFa(y);
	if(siz[fa]>siz[fb]) swap(fa,fb),swap(x,y);
	
	mmp [fa] .clear (), Fa [fa] = fb, siz [fb]+= siz [fa];
	Xor[x]=Xor[y]^z,T=fb,dfs(x,y);
	
	for(;tp;tp--) mmp[T][S[tp]]++;
	add(x,y,z),add(y,x,z);
}

inline void solve(){
	for(int i=n-1;i;i--){
		Merge(u[p[i]],v[p[i]],w[p[i]]);
		ans[n-i]=now;
	}
}

int main(){	
	scanf("%d",&n);
	for(int i=1;i<n;i++) scanf("%d%d%d",u+i,v+i,w+i);
	for(int i=1;i<n;i++) scanf("%d",p+i);
	for(int i=1;i<=n;i++) siz[i]=1,Fa[i]=i,mmp[i][0]=1,Xor[i]=0;
	
	solve();
	
	for(int i=n-1;i>=0;i--) printf("%lld\n",ans[i]);
	return 0;
}

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325126488&siteId=291194637