• 2019下学期第二次个人周赛—A题


    题意:

    如题所示,求 (S(u_1,v_1)) (oplus) (S(u_2,v_2)) 的最大值。

    分析:

    (1).暴力解法:既然 (S(u,v)) 与每个点的祖先有关,那么不难想到一个 (O(n^2)) 的方法计算所有 (S(u,v)) 的值,对每个顶点遍历其祖先暴力计算即可。要算 (S(u_1,v_1)) (oplus) (S(u_2,v_2)) 的最大值,可以暴力 (O(p^{2})) 的计算,其中 (p) 表示去重后所有 (S(u,v)) 的数目。那么总复杂度就是 (O(p^2)) 的,无法通过本题。(p) 的最大值不超过 (20000*15)

    (2).我的解法:可以发现每个顶点的权值很小,只需要用一个数组 (vis[N][16]) 来标记 (u) 的祖先到 (u) 这个节点的异或值,当 (dfs) 遍历 (u) 的儿子 (v) 时,再计算标记 (v) 的异或值即可。这样即可 (O(n*16)) 的得到所有 (S(u,v)) 的值。再用一棵 (01) 字典树边插入边查询最大值即可,总复杂度 (O(p*log_2(p)))

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    #define pb push_back
    
    const int N = 2e4 + 5, M = N * 16 + 5;
    
    int n, u, v, ans, w[N];
    bool val[N][17], flag[M];
    int tot, ch[M * 19][2];
    int head[N], cnt;
    
    struct Graph {
    	int v, next;
    } edge[N << 1];
    
    void addedge(int u, int v) {
    	edge[++cnt].v = v;
    	edge[cnt].next = head[u];
    	head[u] = cnt;
    }
    
    void insert(int p) {
    	int u = 0, x;
    	for (int i = 19; ~i; i--) {
    		x = (p >> i) & 1;
    		if (!ch[u][x]) ch[u][x] = ++tot;
    		u = ch[u][x];
    	}
    }
    
    int query(int p) {
    	int u = 0, x, ans = 0;
    	for (int i = 19; ~i; i--) {
    		x = (p >> i) & 1;
    		if (ch[u][!x]) u = ch[u][!x], ans |= (1 << i);
    		else u = ch[u][x];
    	}
    	return ans;
    }
    
    void dfs(int u, int f) {
    	val[u][w[u]] = true;
    	if (!flag[w[u] * u]) {
    		flag[w[u] * u] = true;
    		insert(w[u] * u);
    		ans = max(ans, query(w[u] * u));
    	}
    	for (int i = head[u]; i; i = edge[i].next) {
    		int v = edge[i].v;
    		if (v == f) continue;
    		for (int j = 0; j <= 15; j++) {
    			if (val[u][j]) {
    				val[v][j ^ w[v]] = true;
    				if (!flag[(j ^ w[v]) * v]) {
    					flag[(j ^ w[v]) * v] = true;
    					insert((j ^ w[v]) * v);
    					ans = max(ans, query((j ^ w[v]) * v));
    				}
    			}
    		}
    		dfs(v, u);
    	}
    }
    
    int main() {
    	scanf("%d", &n);
    	for (int i = 1; i <= n - 1; i++) {
    		scanf("%d %d", &u, &v);
    		addedge(u, v), addedge(v, u);
    	}
    	for (int i = 1; i <= n; i++) scanf("%d", w + i);
    	dfs(1, 0);
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    Director.js路由
    高程第二天
    插件
    Github学习
    高程第一天
    盒子居中显示
    锋利的jq第四天
    锋利的jq第三天
    锋利的jq第二天
    锋利的jq第一天
  • 原文地址:https://www.cnblogs.com/ChaseNo1/p/11745224.html
Copyright © 2020-2023  润新知