JZOJ 5850. 【NOIP提高组模拟2018.8.25】e
第一眼虚树……然而并不需要这么麻烦……
这里的连通块的含义就是这些点到它们lca的链并,所以求出dfs序最小和最大的就行了
用主席树求链上前驱后继
1 #include "bits/stdc++.h" 2 using namespace std; 3 const int N = 2e5 + 10; 4 5 int a[N], head[N], rest[N], to[N]; 6 7 void add(int u, int v) { 8 static int tot = 0; 9 to[++ tot] = v, rest[tot] = head[u], head[u] = tot; 10 } 11 12 int sum[N * 31], lc[N * 31], rc[N * 31], root[N]; 13 14 int nd() { 15 static int tot = 0; 16 return ++ tot; 17 } 18 19 void modify(int last, int now, int l, int r, int pos) { 20 int mid = (l + r) >> 1; 21 sum[now] = sum[last] + 1; 22 lc[now] = lc[last], rc[now] = rc[last]; 23 if(l == r) return ; 24 if(pos <= mid) modify(lc[last], lc[now] = nd(), l, mid, pos); 25 else modify(rc[last], rc[now] = nd(), mid + 1, r, pos); 26 } 27 28 int dfn[N], fa[N][21], dep[N]; 29 30 void dfs(int u) { 31 static int tot = 0; 32 modify(root[fa[u][0]], root[u] = nd(), 1, int(1e9), a[u]); 33 dfn[u] = ++ tot; 34 for(int i = 1 ; i <= 20 ; ++ i) 35 fa[u][i] = fa[fa[u][i - 1]][i - 1]; 36 dep[u] = dep[fa[u][0]] + 1; 37 for(int i = head[u] ; i ; i = rest[i]) { 38 int v = to[i]; 39 if(v == fa[u][0]) continue; 40 fa[v][0] = u; 41 dfs(v); 42 } 43 } 44 45 int pre(int L, int R, int l, int r, int val) { 46 int mid = (l + r) >> 1; 47 if(sum[R] - sum[L] == 0) return -1; 48 else if(l > val) return -1; 49 else if(l == r) { 50 if(sum[R] - sum[L]) return l; 51 else return -1; 52 } else { 53 int tr = pre(rc[L], rc[R], mid + 1, r, val); 54 if(tr != -1) { 55 return tr; 56 } else { 57 return pre(lc[L], lc[R], l, mid, val); 58 } 59 } 60 } 61 62 int sub(int L, int R, int l, int r, int val) { 63 int mid = (l + r) >> 1; 64 if(sum[R] - sum[L] == 0) return -1; 65 else if(r < val) return -1; 66 else if(l == r) { 67 if(sum[R] - sum[L]) return l; 68 else return -1; 69 } else { 70 int tl = sub(lc[L], lc[R], l, mid, val); 71 if(tl != -1) { 72 return tl; 73 } else { 74 return sub(rc[L], rc[R], mid + 1, r, val); 75 } 76 } 77 } 78 79 int n, q, type, lastans, p[N]; 80 81 bool cmp(int a, int b) { 82 return dfn[a] < dfn[b]; 83 } 84 85 int getlca(int u, int v) { 86 if(dep[u] < dep[v]) swap(u, v); 87 for(int i = 20 ; ~ i ; -- i) if(dep[fa[u][i]] >= dep[v]) u = fa[u][i]; 88 if(u == v) return u; 89 for(int i = 20 ; ~ i ; -- i) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; 90 return fa[u][0]; 91 } 92 93 int query(int val, int u, int v) { 94 int PRE = pre(root[fa[u][0]], root[v], 1, int(1e9), val); 95 int SUB = sub(root[fa[u][0]], root[v], 1, int(1e9), val); 96 if(PRE != -1 && SUB != -1) return min(abs(val - PRE), abs(val - SUB)); 97 if(PRE == -1 && SUB == -1) return int(1e9); 98 if(PRE == -1) swap(PRE, SUB); return abs(val - PRE); 99 } 100 101 int sol(int val, int k) { 102 for(int i = 1 ; i <= k ; ++ i) { 103 scanf("%d", &p[i]); 104 if(type) p[i] = (p[i] - 1 + lastans) % n + 1; 105 } 106 int mn = p[1], mx = p[1]; 107 for(int i = 1 ; i <= k ; ++ i) { 108 if(dfn[p[i]] < dfn[mn]) mn = p[i]; 109 if(dfn[p[i]] > dfn[mx]) mx = p[i]; 110 } 111 int lca = getlca(mn, mx); 112 int ans = 1e9; 113 for(int i = 1 ; i <= k ; ++ i) 114 ans = min(ans, query(val, lca, p[i])); 115 return ans; 116 } 117 118 int main() { 119 freopen("e.in", "r", stdin); 120 freopen("e.out", "w", stdout); 121 scanf("%d%d%d", &n, &q, &type); 122 for(int i = 1 ; i <= n ; ++ i) { 123 scanf("%d", &a[i]); 124 } 125 for(int i = 1, u, v ; i < n ; ++ i) { 126 scanf("%d%d", &u, &v); 127 add(u, v), add(v, u); 128 } 129 dfs(1); 130 for(int i = 1, val, k ; i <= q ; ++ i) { 131 scanf("%d%d", &val, &k); 132 printf("%d\n", lastans = sol(val, k)); 133 } 134 }
1 #include "bits/stdc++.h" 2 using namespace std; 3 const int N = 2e5 + 10; 4 5 int a[N], head[N], rest[N], to[N]; 6 7 void add(int u, int v) { 8 static int tot = 0; 9 to[++ tot] = v, rest[tot] = head[u], head[u] = tot; 10 } 11 12 int sum[N * 31], lc[N * 31], rc[N * 31], root[N]; 13 14 int nd() { 15 static int tot = 0; 16 return ++ tot; 17 } 18 19 void modify(int last, int now, int l, int r, int pos) { 20 int mid = (l + r) >> 1; 21 sum[now] = sum[last] + 1; 22 lc[now] = lc[last], rc[now] = rc[last]; 23 if(l == r) return ; 24 if(pos <= mid) modify(lc[last], lc[now] = nd(), l, mid, pos); 25 else modify(rc[last], rc[now] = nd(), mid + 1, r, pos); 26 } 27 28 int dfn[N], l[N], r[N], fa[N][21], dep[N]; 29 30 void dfs(int u) { 31 static int tot = 0; 32 modify(root[fa[u][0]], root[u] = nd(), 1, int(1e9), a[u]); 33 dfn[u] = ++ tot, l[u] = tot; 34 for(int i = 1 ; i <= 20 ; ++ i) 35 fa[u][i] = fa[fa[u][i - 1]][i - 1]; 36 dep[u] = dep[fa[u][0]] + 1; 37 for(int i = head[u] ; i ; i = rest[i]) { 38 int v = to[i]; 39 if(v == fa[u][0]) continue; 40 fa[v][0] = u; 41 dfs(v); 42 } 43 r[u] = tot; 44 } 45 46 int pre(int L, int R, int l, int r, int val) { 47 int mid = (l + r) >> 1; 48 if(sum[R] - sum[L] == 0) return -1; 49 else if(l > val) return -1; 50 else if(l == r) { 51 if(sum[R] - sum[L]) return l; 52 else return -1; 53 } else { 54 int tr = pre(rc[L], rc[R], mid + 1, r, val); 55 if(tr != -1) { 56 return tr; 57 } else { 58 return pre(lc[L], lc[R], l, mid, val); 59 } 60 } 61 } 62 63 int sub(int L, int R, int l, int r, int val) { 64 int mid = (l + r) >> 1; 65 if(sum[R] - sum[L] == 0) return -1; 66 else if(r < val) return -1; 67 else if(l == r) { 68 if(sum[R] - sum[L]) return l; 69 else return -1; 70 } else { 71 int tl = sub(lc[L], lc[R], l, mid, val); 72 if(tl != -1) { 73 return tl; 74 } else { 75 return sub(rc[L], rc[R], mid + 1, r, val); 76 } 77 } 78 } 79 80 int n, q, type, lastans, p[N]; 81 82 bool cmp(int a, int b) { 83 return dfn[a] < dfn[b]; 84 } 85 86 int getlca(int u, int v) { 87 if(dep[u] < dep[v]) swap(u, v); 88 for(int i = 20 ; ~ i ; -- i) if(dep[fa[u][i]] >= dep[v]) u = fa[u][i]; 89 if(u == v) return u; 90 for(int i = 20 ; ~ i ; -- i) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; 91 return fa[u][0]; 92 } 93 94 int query(int val, int u, int v) { 95 int PRE = pre(root[fa[u][0]], root[v], 1, int(1e9), val); 96 int SUB = sub(root[fa[u][0]], root[v], 1, int(1e9), val); 97 if(PRE != -1 && SUB != -1) return min(abs(val - PRE), abs(val - SUB)); 98 if(PRE == -1 && SUB == -1) return int(1e9); 99 if(PRE == -1) swap(PRE, SUB); return abs(val - PRE); 100 } 101 102 int sol(int val, int k) { 103 for(int i = 1 ; i <= k ; ++ i) { 104 scanf("%d", &p[i]); 105 p[i] = (p[i] - 1 + lastans * type) % n + 1; 106 } 107 sort(p + 1, p + 1 + k, cmp); 108 for(int i = k ; i >= 2 ; -- i) { 109 p[++ k] = getlca(p[i], p[i - 1]); 110 } 111 sort(p + 1, p + 1 + k, cmp); 112 k = unique(p + 1, p + 1 + k) - p - 1; 113 stack<int> s; 114 int ans = 1e9; 115 for(int i = 1 ; i <= k ; ++ i) { 116 int v = p[i]; 117 if(s.empty()) { 118 s.push(v); 119 ans = min(ans, abs(a[v] - val)); 120 } else { 121 int u = s.top(); 122 while(s.size() && r[u] < l[v]) { 123 s.pop(); 124 if(s.size()) u = s.top(); 125 } 126 if(s.size()) { 127 ans = min(ans, query(val, u, v)); 128 } 129 s.push(v); 130 } 131 } 132 return ans; 133 } 134 135 int main() { 136 freopen("e.in", "r", stdin); 137 freopen("e.out", "w", stdout); 138 scanf("%d%d%d", &n, &q, &type); 139 for(int i = 1 ; i <= n ; ++ i) { 140 scanf("%d", &a[i]); 141 } 142 for(int i = 1, u, v ; i < n ; ++ i) { 143 scanf("%d%d", &u, &v); 144 add(u, v), add(v, u); 145 } 146 dfs(1); 147 for(int i = 1, val, k ; i <= q ; ++ i) { 148 scanf("%d%d", &val, &k); 149 printf("%d\n", lastans = sol(val, k)); 150 } 151 }
论如何优雅的构造一棵虚树:
1. 将所有查询点放到数组中,按照dfs序排序
2. 将相邻两个点的lca放入dfs序中,然后再按照dfs序排序
3. 开一个stack,扫一遍,dfs序相当于括号序,于是就可以得知每个点的父亲节点是哪个
4. 连边,然后做完了(甚至可以直接拓扑排序,因为一个点出栈的前提是子树中的节点都访问完)