zoukankan      html  css  js  c++  java
  • [BZOJ5361][Lydsy1805月赛]对称数

    [BZOJ5361][Lydsy1805月赛]对称数

    试题描述

    小 Q 认为,偶数具有对称美,而奇数则没有。

    给定一棵 (n) 个点的树,任意两点之间有且仅有一条直接或间接路径。这些点编号依次为 (1)(n),其中编号为 (i) 的点上有一个正整数 (a_i)

    定义集合 (S(u, v))(u) 点到 (v) 点的唯一最短路径上经过的所有点 (x)(包括 (u)(v)) 对应的正整数 (a_x) 的集合。小 Q 将在 (m)(S(u, v)) 中寻找最小的对称数。因为偶数具有对称美,所以对称数是指那些出现了偶数次 (包括 (0) 次) 的正整数。

    请写一个程序,帮助小 Q 找到最小的对称数。

    输入

    第一行包含一个正整数 (T(1 le T le 10)),表示测试数据的组数。

    每组数据第一行包含两个正整数 (n, m(1 le n, m le 200000)),分别表示点数和询问数。

    第二行包含 (n) 个正整数 (a_1, a_2, cdots, a_n(1 le a_i le 200000)),依次表示每个点上的数字。

    接下来 (n - 1) 行,每行两个正整数 (u_i, v_i(1 ≤ u_i, v_i le n, u_i e v_i)),表示一条连接 (u_i)(v_i) 的双向树边。

    接下来 (m) 行,每行两个正整数 (u_i, v_i(1 le u_i, v_i le n)),依次表示每个询问。

    输出

    对于每个询问输出一行一个正整数,即最小的对称数。

    输入示例

    1
    5 3
    1 2 2 1 3
    1 2
    1 3
    2 4
    2 5
    2 3
    1 4
    2 5
    

    输出示例

    2
    1
    1
    

    数据规模及约定

    见“输入

    题解

    偶然间发现一道水题,发现很可切,就顺手切了一下。

    这题一眼树上莫队([捂脸]然后就一脸的不想做),但是看一下 (12 exttt{s}) 十组数据肯定不是这个复杂度啊,肯定有其他办法……

    于是有想了什么询问离线然后点分治……后来发现这样不太可做。

    想了一会,突然发现这不是不久前做过的一道题吗?

    奇偶性,自然想到用 (01) 串表示,合并信息的时候直接异或,既然异或了,不妨直接维护每个节点到根节点这条链上的颜色的奇偶情况……然后这题解法就出来了。

    用主席树维护每个节点到根节点上的所有颜色奇偶性组成的 (01) 串的区间哈希值。询问就是查询两个 (01) 串异或之后的第一个 (0) 的位置,直接在线段树上二分即可(就是看两个串的前缀异或起来是否等于全 (1) 串的哈希值)。这里用异或哈希,就是给每种颜色随机一种 unsigned long long 的哈希值,然后 (01) 串的哈希值就是所有 (1) 的位置对应的颜色的哈希值异或起来。

    注意这里是点权,所以 lca 那里得再异或一下补上。

    #include <bits/stdc++.h>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 200010
    #define maxm 400010
    #define maxlog 18
    #define UL unsigned long long
    
    UL hval[maxn], hpre[maxn];
    UL randUL() {
    	UL x = 0, t = (1 << 8) - 1;
    	rep(i, 1, 8) x = (x << 8) | (rand() & t);
    	return x;
    }
    
    int n, m, head[maxn], nxt[maxm], to[maxm], col[maxn];
    
    void AddEdge(int a, int b) {
    	to[++m] = b; nxt[m] = head[a]; head[a] = m;
    	swap(a, b);
    	to[++m] = b; nxt[m] = head[a]; head[a] = m;
    	return ;
    }
    
    int M;
    namespace Sgt {
    	const int maxnode = 7200010;
    	
    	int ToT, lc[maxnode], rc[maxnode];
    	UL hsum[maxnode];
    	
    	void clear() {
    		memset(lc, 0, sizeof(int) * (ToT + 1));
    		memset(rc, 0, sizeof(int) * (ToT + 1));
    		memset(hsum, 0, sizeof(UL) * (ToT + 1));
    		ToT = 0;
    		return ;
    	}
    	
    	void update(int &y, int x, int l, int r, int p, UL v) {
    		hsum[y = ++ToT] = hsum[x] ^ v;
    		if(l == r) return ;
    		int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
    		if(p <= mid) update(lc[y], lc[x], l, mid, p, v);
    		else update(rc[y], rc[x], mid + 1, r, p, v);
    		return ;
    	}
    	
    	int Query(int u, int v, int c) {
    		int pos = col[c], l = 1, r = M;
    		while(l < r) {
    			int mid = l + r >> 1;
    			if((hpre[mid] ^ hpre[l-1]) == (hsum[lc[u]] ^ hsum[lc[v]] ^ (l <= pos && pos <= mid) * hval[pos])) l = mid + 1, u = rc[u], v = rc[v];
    			else r = mid, u = lc[u], v = lc[v];
    		}
    		if((hpre[l] ^ hpre[l-1]) == (hsum[u] ^ hsum[v] ^ (l == pos) * hval[pos])) l++;
    		return l;
    	}
    }
    
    int rt[maxn], fa[maxn][maxlog], dep[maxn];
    void build(int u) {
    	rep(i, 1, maxlog - 1) fa[u][i] = fa[fa[u][i-1]][i-1];
    	rt[u] = rt[fa[u][0]]; Sgt::update(rt[u], rt[u], 1, M, col[u], hval[col[u]]);
    	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u][0]) fa[to[e]][0] = u, dep[to[e]] = dep[u] + 1, build(to[e]);
    	return ;
    }
    int lca(int a, int b) {
    	if(dep[a] < dep[b]) swap(a, b);
    	dwn(i, maxlog - 1, 0) if(dep[a] - (1 << i) >= dep[b]) a = fa[a][i];
    	dwn(i, maxlog - 1, 0) if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i];
    	return a == b ? a : fa[b][0];
    }
    
    void work() {
    	n = read();
    	m = 0; memset(head, 0, sizeof(head));
    	int q = read(); M = 0;
    	rep(i, 1, n) col[i] = read(), M = max(M, col[i]);
    	rep(i, 1, M) hval[i] = randUL(), hpre[i] = hpre[i-1] ^ hval[i];
    	rep(i, 1, n - 1) {
    		int a = read(), b = read();
    		AddEdge(a, b);
    	}
    	Sgt::clear(); memset(rt, 0, sizeof(rt));
    	build(1);
    	while(q--) {
    		int u = read(), v = read();
    		printf("%d
    ", Sgt::Query(rt[u], rt[v], lca(u, v)));
    	}
    	return ;
    }
    
    int main() {
    	int T = read();
    	
    	while(T--) work();
    	
    	return 0;
    }
    
  • 相关阅读:
    LINQPad_批量修改图片名称
    1.2_php验证码
    1.1_php基础语法
    移动管理后台
    [Swift]LeetCode1137. 第 N 个泰波那契数 | N-th Tribonacci Number
    [Swift]LeetCode1136. 平行课程 | Parallel Courses
    [Swift]LeetCode1135. 最低成本联通所有城市 | Connecting Cities With Minimum Cost
    [Swift]LeetCode1134. 阿姆斯特朗数 | Armstrong Number
    [Swift]LeetCode1133. 最大唯一数 | Largest Unique Number
    企业
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/9097771.html
Copyright © 2011-2022 走看看