Submission #1196659

#TimeUsernameProblemLanguageResultExecution timeMemory
1196659APROHACKKlasika (COCI20_klasika)C++20
0 / 110
113 ms40520 KiB
#include<bits/stdc++.h>

#define ff first
#define ss second 
#define pb push_back
#define sz(a) ((int)((a).size()))
#define inf 1e9
using ll = long long;
using ld = long double;

using namespace std;
const int N = 200005;
struct query{
	int a, b, XORab, id, last_node;
};

vector<query>queries;

const int MX = 200000 * 30;

int go[MX][2];
int first[MX];
int lazy[MX];

struct TRIE{
	private: 
		int nxt;

		int generate_node(){
			go[nxt][0] = -1;
			go[nxt][1] = -1;
			first[nxt] = INT_MAX;
			lazy[nxt] = 0;
			return nxt ++ ;
		}

		void propagate(int u, int bit){
			if(lazy[u] == 0)return ;
			if((lazy[u] >> bit) & 1){
				swap(go[u][0], go[u][1]);
			}
			if(go[u][0] != -1){
				lazy[go[u][0]] ^= lazy[u];
			}
			if(go[u][1] != -1){
				lazy[go[u][1]] ^= lazy[u];
			}
			lazy[u] = 0;
		}

		

		int find_maximum(int u, int x, int bit, int &last_node){
			if(bit >= 0){
				propagate(u, bit);
			}
			
			if(bit == -1){
				return 0;
			}
			if((1 << bit) & x){
				// wants 0
				if(go[u][0] != -1 && first[go[u][0]] <= last_node){
					// cout << "move " << 0 << endl;
					return (1 << bit) + find_maximum(go[u][0], x, bit - 1, last_node);
				}else{
					// cout << "move " << 1 << endl;
					return find_maximum(go[u][0], x, bit - 1, last_node);;
				}
			}else{
				// wants 1
				if(go[u][1] != -1 && first[go[u][1]] <= last_node){
					// cout << "move " << 1 << endl;
					return (1 << bit) + find_maximum(go[u][1], x, bit - 1, last_node);
				}else{
					// cout << "move " << 0 << endl;
					return find_maximum(go[u][0], x, bit - 1, last_node);
				}
			}
		}

		void insert_value(int u, int &x, int bit, int &time){
			if(bit >= 0){
				propagate(u, bit);
			}
			first[u] = min(first[u], time);

			if(bit == -1){
		
				return ;
			}

			if((1 << bit) & x){
				if(go[u][1] == -1)go[u][1] = generate_node();
				insert_value(go[u][1], x, bit - 1, time);
			}else{
				if(go[u][0] == -1)go[u][0] = generate_node();
				insert_value(go[u][0], x, bit - 1, time);
			}
		}

	public:

		void reinit (){
			nxt = 1;
			go[0][0] = - 1;
			go[0][1] = -1;
			first[0] = INT_MAX;
			lazy[0] = 0;
			#ifdef LOCAL
			// cout << "reinit " << endl;
			#endif
		}

		int find_maximum(int x, int last_node){
			return find_maximum(0, x, 30, last_node);
		}

		void insert_value(int x, int time){
			insert_value(0, x, 30, time);
			#ifdef LOCAL
			// cout << x << " " << time << " inserted " << endl;
			#endif
		}

		TRIE(){

		}



};





vector<pair<int, int> >adj[N];
vector<query>queries_node[N];
int parent[N];
int parent_weight[N];

int sparse[N][20];
int XOR[N][20];
int depth[N];
int sz[N];
int ans_query[N];

int last_node;

struct LCA{
	
	
	LCA(){
		for(int i = 1 ; i <= last_node ; ++ i){
			sparse[i][0] = parent[i];
			XOR[i][0] = parent_weight[i];
		}

		for(int b = 1 ; b < 20 ; ++ b){
			for(int i = 1 ; i <= last_node ; ++ i){
				sparse[i][b] = sparse[sparse[i][b - 1]][b - 1];
				XOR[i][b] = XOR[sparse[i][b - 1]][b - 1] ^ XOR[i][b - 1];
			}
		}
	}

	int find_xor(int a, int b){
		if(a == b)return 0;

		if(depth[a] < depth[b])swap(a, b);
		// A is deeper

		int distancia = depth[a] - depth[b];
		int ans = 0;

		for(int bit = 19 ; bit >= 0 ; -- bit){
			if((1 << bit) & distancia){
				ans ^= XOR[a][bit];
				a = sparse[a][bit];
			}
		}

		// A is at the same depth as B

		if(a == b)return ans;

		for(int bit = 19 ; bit >= 0 ; -- bit){
			if(sparse[a][bit] == sparse[b][bit])continue;
			ans ^= XOR[a][bit];
			ans ^= XOR[b][bit];
			a = sparse[a][bit];
			b = sparse[b][bit];
		}

		// Subir uno mas
		ans ^= XOR[a][0];
		ans ^= XOR[b][0];
		return ans;
	}
};

void dfs_construct(int u, int d){
	sz[u] = 1;
	depth[u] = d;
	for(auto &c : adj[u]){
		dfs_construct(c.ff, d + 1);
		sz[u] += sz[c.ff];
	}
}

vector<pair<int, int>>distances;

void find_subtree(int u, int x){
	distances.push_back({x, u});
	for(auto &c : adj[u]){
		int v = c.ff;
		int w = c.ss;
		find_subtree(v, x ^ w);
	}
}

TRIE trie;

void dfs_solve(int u, int is_big){

	for(auto &c : adj[u]){
		int v = c.ff;
		int w = c.ss;
		dfs_solve(v, false);
	}

	if(queries_node[u].empty())return ;

	distances.clear();
	find_subtree(u, 0);
	trie.reinit();

	for(int i = 0 ; i < distances.size() ; ++ i){
		trie.insert_value(distances[i].ff, distances[i].ss);
	}

	for(auto &query : queries_node[u]){
		ans_query[query.id] = trie.find_maximum(query.XORab, query.last_node);
	}
}




int main(){
    #ifdef LOCAL
		//freopen("in","r", stdin);
	#endif
	ios_base::sync_with_stdio(0); cin.tie(0);

	int q;
	cin >> q;
	last_node = 1;
	parent[1] = 1;
	for(int i = 0 ; i < q ; ++ i){
		string type ;
		cin >> type;
		if(type == "Add"){
			int x, y;
			cin >> x >> y;
			parent[ ++ last_node] = x;
			parent_weight[last_node] = y;
			adj[x].push_back({last_node , y});
		}else{
			int a, b;
			cin >> a >> b;
			queries.push_back({a, b, -1, i, last_node});
		}
	}

	dfs_construct(1, 0);

	LCA lca;


	for(int i = 0 ; i < queries.size() ; ++ i){
		queries[i].XORab = lca.find_xor(queries[i].a, queries[i].b);
		queries_node[queries[i].b].pb(queries[i]);
	}

	dfs_solve(1, 0);

	for(int i = 0 ; i < queries.size() ; ++ i){
		cout << ans_query[queries[i].id] << "\n";
	}

	
    return 0;
}


#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...