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 }
dfs序+lca+主席树 JZOJ 5850. 【NOIP提高组模拟2018.8.25】e
  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 }
虚树 JZOJ 5850. 【NOIP提高组模拟2018.8.25】e

论如何优雅的构造一棵虚树:

1. 将所有查询点放到数组中,按照dfs序排序

2. 将相邻两个点的lca放入dfs序中,然后再按照dfs序排序

3. 开一个stack,扫一遍,dfs序相当于括号序,于是就可以得知每个点的父亲节点是哪个

4. 连边,然后做完了(甚至可以直接拓扑排序,因为一个点出栈的前提是子树中的节点都访问完)

posted @ 2018-08-26 09:03  KingSann  阅读(126)  评论(0编辑  收藏  举报