薛的lca讲课配到题解

2.15 LCA

 

Nearest Common Ancestors POJ 1330

题意:给出一棵树, 询问两个点的最近公共祖先。

思路:

$LCA$模板题,请各位掏出各式各样的模板A穿它。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<queue>
  6 
  7 using namespace std;
  8 
  9 typedef long long ll;
 10 const int maxn = 1e4 + 10;
 11 const int DEG = 20;
 12 
 13 struct Edge {
 14     int to, nxt;
 15     Edge() {}
 16     Edge(int to, int nxt) :to(to), nxt(nxt) {}
 17 }edge[maxn << 1];
 18 
 19 int head[maxn], tot;
 20 
 21 void Init()
 22 {
 23     tot = 0;
 24     memset(head, -1, sizeof head);
 25 }
 26 
 27 void addedge(int u, int v)
 28 {
 29     edge[tot] = Edge(v, head[u]); head[u] = tot++;
 30     edge[tot] = Edge(u, head[v]); head[v] = tot++;
 31 }
 32 
 33 int fa[maxn][DEG];
 34 int deg[maxn];
 35 
 36 void BFS(int root)
 37 {
 38     queue<int>q;
 39     deg[root] = 0;
 40     fa[root][0] = root;
 41     q.push(root);
 42     while (!q.empty())
 43     {
 44         int tmp = q.front();
 45         q.pop();
 46         for (int i = 1; i < DEG; ++i)
 47         {
 48             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
 49         }
 50         for (int i = head[tmp]; i != -1; i = edge[i].nxt)
 51         {
 52             int v = edge[i].to;
 53             if (v == fa[tmp][0]) continue;
 54             deg[v] = deg[tmp] + 1;
 55             fa[v][0] = tmp;
 56             q.push(v);
 57         }
 58     }
 59 }
 60 
 61 int LCA(int u, int v)
 62 {
 63     if (deg[u] > deg[v]) swap(u, v);
 64     int hu = deg[u];
 65     int hv = deg[v];
 66     int tu = u, tv = v;
 67     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
 68     {
 69         if (det & 1)
 70         {
 71             tv = fa[tv][i];
 72         }
 73     }
 74     if (tu == tv) return tu;
 75     for (int i = DEG - 1; i >= 0; --i)
 76     {
 77         if (fa[tu][i] == fa[tv][i])
 78             continue;
 79         tu = fa[tu][i];
 80         tv = fa[tv][i];
 81     }
 82     return fa[tu][0];
 83 }
 84 
 85 int n;
 86 bool flag[maxn];
 87 
 88 void RUN()
 89 {
 90     int t;
 91     scanf("%d", &t);
 92     while (t--)
 93     {
 94         scanf("%d", &n);
 95         Init();
 96         memset(flag, false, sizeof flag);
 97         for (int i = 1; i < n; ++i)
 98         {
 99             int u, v;
100             ll w;
101             scanf("%d %d", &u, &v);
102             addedge(u, v);
103             flag[v] = true;
104         }
105         int root = 0;
106         for (int i = 1; i <= n; ++i)
107         {
108             if (!flag[i])
109             {
110                 root = i;
111                 break;
112             }
113         }
114         BFS(root);
115         int u, v;
116         scanf("%d %d", &u, &v);
117         printf("%d\n", LCA(u, v));
118     }
119 }
120 
121 int main()
122 {
123 #ifdef LOCAL_JUDGE
124     freopen("Text.txt", "r", stdin);
125 #endif // LOCAL_JUDGE
126 
127     RUN();
128 
129 #ifdef LOCAL_JUDGE
130     fclose(stdin);
131 #endif // LOCAL_JUDGE
132     return 0;
133 }
View Code

 

Closest Common Ancestors POJ 1470

题意:给出一棵树,然后给出几组询问,记录每个点作为询问中的最近公共祖先的次数并输出,如果次数为0则不输出。

思路:

$LCA$模板题,建图稍微注意一下后对于每次询问都记录他的最近最近公共祖先,输出。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<queue>
  7 
  8 using namespace std;
  9 
 10 typedef long long ll;
 11 const int maxn = 1e5 + 10;
 12 const int DEG = 20;
 13 
 14 struct Edge {
 15     int to, nxt;
 16     Edge() {}
 17     Edge(int to, int nxt) :to(to), nxt(nxt) {}
 18 }edge[maxn << 1];
 19 
 20 int head[maxn], tot;
 21 
 22 int dis[maxn];
 23 
 24 void addedge(int u, int v)
 25 {
 26     edge[tot] = Edge(v, head[u]);
 27     head[u] = tot++;
 28 }
 29 
 30 void Init()
 31 {
 32     tot = 0;
 33     memset(head, -1, sizeof head);
 34 }
 35 
 36 int fa[maxn][DEG];
 37 int deg[maxn];
 38 
 39 void BFS(int root)
 40 {
 41     queue<int>q;
 42     deg[root] = 0;
 43     fa[root][0] = root;
 44     q.push(root);
 45     while (!q.empty())
 46     {
 47         int tmp = q.front();
 48         q.pop();
 49         for (int i = 1; i < DEG; ++i)
 50         {
 51             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
 52         }
 53         for (int i = head[tmp]; i != -1; i = edge[i].nxt)
 54         {
 55             int v = edge[i].to;
 56             if (v == fa[tmp][0]) continue;
 57             deg[v] = deg[tmp] + 1;
 58             fa[v][0] = tmp;
 59             q.push(v);
 60         }
 61     }
 62 }
 63 
 64 int LCA(int u, int v)
 65 {
 66     if (deg[u] > deg[v]) swap(u, v);
 67     int hu = deg[u];
 68     int hv = deg[v];
 69     int tu = u, tv = v;
 70     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
 71     {
 72         if (det & 1)
 73         {
 74             tv = fa[tv][i];
 75         }
 76     }
 77     if (tu == tv) return tu;
 78     for (int i = DEG - 1; i >= 0; --i)
 79     {
 80         if (fa[tu][i] == fa[tv][i])
 81             continue;
 82         tu = fa[tu][i];
 83         tv = fa[tv][i];
 84     }
 85     return fa[tu][0];
 86 }
 87 
 88 int n, m;
 89 char str[maxn];
 90 bool flag[maxn];
 91 int arr[maxn];
 92 
 93 void RUN()
 94 {
 95     while (~scanf("%d", &n))
 96     {
 97         Init();
 98         memset(flag, false, sizeof flag);
 99         memset(arr, 0, sizeof arr);
100         for (int i = 1; i <= n; ++i)
101         {
102             int id, m;
103             scanf("%d:(%d)", &id, &m);
104             for (int i = 0; i < m; ++i)
105             {
106                 int id2;
107                 scanf("%d", &id2);
108                 addedge(id, id2);
109                 flag[id2] = true;
110             }
111         }
112         int root = 0;
113         for (int i = 1; i <= n; ++i)
114         {
115             if (!flag[i])
116             {
117                 root = i;
118                 break;
119             }
120         }
121         BFS(root);
122         int q;
123         scanf("%d", &q);
124         while (q--)
125         {
126             int u, v;
127             scanf(" (%d %d)", &u, &v);
128             int root = LCA(u, v);
129             arr[root]++;
130         }
131         for (int i = 1; i <= n; ++i)
132         {
133             if (arr[i])
134             {
135                 printf("%d:%d\n", i, arr[i]);
136             }
137         }
138     }
139 }
140 
141 int main()
142 {
143 #ifdef LOCAL_JUDGE
144     freopen("Text.txt", "r", stdin);
145 #endif // LOCAL_JUDGE
146 
147     RUN();
148 
149 #ifdef LOCAL_JUDGE
150     fclose(stdin);
151 #endif // LOCAL_JUDGE
152     return 0;
153 }
View Code

 

How far away ?HDU 2586

题意:给出一棵树,每条边有边权,然后给出几组询问,每组询问需要输出$u, v$之间的最短路径。

思路:

对于一棵树,两个点的路径唯一。

这两个点的路径长度为u到根的路径长度加上v到根的路径长度减去两倍LCA(u, v)到根的路径长度。

即$dis_u+dis_v-2 \cdot dis_{LCA_{u, v}}$。

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 
  7 const int maxn = 1e5 + 10;
  8 const int DEG = 20;
  9 
 10 int dis[maxn];
 11 
 12 struct Edge {
 13     int  to;
 14     int next;
 15     int w;
 16     Edge() {}
 17     Edge(int to, int next, int w) :to(to), next(next), w(w) {}
 18 }edge[maxn << 1];
 19 
 20 int head[maxn];
 21 int tot;
 22 
 23 void addedge(int u, int v, int w)
 24 {
 25     edge[tot] = Edge(v, head[u], w);
 26     head[u] = tot++;
 27 }
 28 
 29 void init()
 30 {
 31     tot = 0;
 32     memset(head, -1, sizeof head);
 33     memset(dis, 0x3f, sizeof dis);
 34 }
 35 
 36 int fa[maxn][DEG];
 37 int deg[maxn];
 38 
 39 void BFS(int root)
 40 {
 41     queue<int>q;
 42     deg[root] = 0;
 43     fa[root][0] = root;
 44     q.push(root);
 45     dis[root] = 0;
 46     while (!q.empty())
 47     {
 48         int tmp = q.front();
 49         q.pop();
 50         for (int i = 1; i < DEG; ++i)
 51         {
 52             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
 53         }
 54         for (int i = head[tmp]; i != -1; i = edge[i].next)
 55         {
 56             int v = edge[i].to;
 57             if (v == fa[tmp][0]) continue;
 58             dis[v] = dis[tmp] + edge[i].w;
 59             deg[v] = deg[tmp] + 1;
 60             fa[v][0] = tmp;
 61             q.push(v);
 62         }
 63     }
 64 }
 65 
 66 int LCA(int u, int v)
 67 {
 68     if (deg[u] > deg[v])
 69         swap(u, v);
 70     int hu = deg[u], hv = deg[v];
 71     int tu = u;
 72     int tv = v;
 73     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
 74     {
 75         if (det & 1)
 76         {
 77             tv = fa[tv][i];
 78         }
 79     }
 80     if (tu == tv) return tu;
 81     for (int i = DEG - 1; i >= 0; --i)
 82     {
 83         if (fa[tu][i] == fa[tv][i])
 84             continue;
 85         tu = fa[tu][i];
 86         tv = fa[tv][i];
 87     }
 88     return fa[tu][0];
 89 }
 90 
 91 void RUN()
 92 {
 93     int t;
 94     scanf("%d", &t);
 95     while (t--)
 96     {
 97         init();
 98         int n, q;
 99         scanf("%d %d", &n, &q);
100         for (int i = 1; i < n; ++i)
101         {
102             int u, v, w;
103             scanf("%d %d %d", &u, &v, &w);
104             addedge(u, v, w);
105             addedge(v, u, w);
106         }
107         BFS(1);
108         while (q--)
109         {
110             int u, v;
111             scanf("%d %d", &u, &v);
112             int root = LCA(u, v);
113             int ans = dis[u] + dis[v] - 2 * dis[root];
114             printf("%d\n", ans);
115         }
116     }
117 }
118 
119 int main()
120 {
121 #ifdef LOCAL_JUDGE
122     freopen("Text.txt", "r", stdin);
123 #endif // LOCAL_JUDGE
124 
125     RUN();
126 
127 #ifdef LOCAL_JUDGE
128     fclose(stdin);
129 #endif // LOCAL_JUDGE
130     return 0;
131 }
View Code

 

Connections between cities HDU 2874

题意:给出一张图,保证无环,但是不保证连通,求出两个点的最短距离,如果不连通就输出$"Not connected"$。

思路:

由于保证无环,那么给出的图就是一颗或者多颗树。

那么可以用并查集来维护两点是否在一个集合中,也就是一棵树中。

对于在一棵树上的$u,v$两点,距离就是$dis_u+dis_v-2 \cdot dis_{LCA_{u, v}}$。

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 
  7 const int maxn = 1e5 + 10;
  8 const int DEG = 20;
  9 
 10 int n, m, q;
 11 int Fa[maxn];
 12 
 13 int dis[maxn];
 14 
 15 int find(int x)
 16 {
 17     return x == Fa[x] ? Fa[x] : Fa[x] = find(Fa[x]);
 18 }
 19 
 20 void mix(int x, int y)
 21 {
 22     x = find(x);
 23     y = find(y);
 24     if (x != y)
 25     {
 26         Fa[x] = y;
 27     }
 28 }
 29 
 30 struct Edge {
 31     int  to;
 32     int next;
 33     int w;
 34     Edge() {}
 35     Edge(int to, int next, int w) :to(to), next(next), w(w) {}
 36 }edge[maxn << 1];
 37 
 38 int head[maxn];
 39 int tot;
 40 
 41 void addedge(int u, int v, int w)
 42 {
 43     edge[tot] = Edge(v, head[u], w);
 44     head[u] = tot++;
 45 }
 46 
 47 void init()
 48 {
 49     tot = 0;
 50     memset(head, -1, sizeof head);
 51     memset(dis, 0, sizeof dis);
 52     for (int i = 1; i <= n; ++i)
 53     {
 54         Fa[i] = i;
 55     }
 56 }
 57 
 58 int fa[maxn][DEG];
 59 int deg[maxn];
 60 
 61 void BFS()
 62 {
 63     queue<int>q;
 64     for (int i = 1; i <= n; ++i)
 65     {
 66         if (find(i) == i)
 67         {
 68             deg[i] = 0;
 69             fa[i][0] = i;
 70             dis[i] = 0;
 71             q.push(i);
 72         }
 73     }
 74     while (!q.empty())
 75     {
 76         int tmp = q.front();
 77         q.pop();
 78         for (int i = 1; i < DEG; ++i)
 79         {
 80             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
 81         }
 82         for (int i = head[tmp]; i != -1; i = edge[i].next)
 83         {
 84             int v = edge[i].to;
 85             if (v == fa[tmp][0]) continue;
 86             dis[v] = dis[tmp] + edge[i].w;
 87             deg[v] = deg[tmp] + 1;
 88             fa[v][0] = tmp;
 89             q.push(v);
 90         }
 91     }
 92 }
 93 
 94 int LCA(int u, int v)
 95 {
 96     if (deg[u] > deg[v])
 97         swap(u, v);
 98     int hu = deg[u], hv = deg[v];
 99     int tu = u;
100     int tv = v;
101     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
102     {
103         if (det & 1)
104         {
105             tv = fa[tv][i];
106         }
107     }
108     if (tu == tv) return tu;
109     for (int i = DEG - 1; i >= 0; --i)
110     {
111         if (fa[tu][i] == fa[tv][i])
112             continue;
113         tu = fa[tu][i];
114         tv = fa[tv][i];
115     }
116     return fa[tu][0];
117 }
118 
119 void solve()
120 {
121     int u, v;
122     scanf("%d %d", &u, &v);
123     int rootu = find(u);
124     int rootv = find(v);
125     if (rootu != rootv)
126     {
127         puts("Not connected");
128         return;
129     }
130     int root = LCA(u, v);
131     int ans = dis[u] + dis[v] - 2 * dis[root];
132     printf("%d\n", ans);
133 }
134 
135 void RUN()
136 {
137     while (~scanf("%d %d %d", &n, &m, &q))
138     {
139         init();
140         for (int i = 0; i < m; ++i)
141         {
142             int u, v, w;
143             scanf("%d %d %d", &u, &v, &w);
144             addedge(u, v, w);
145             addedge(v, u, w);
146             mix(u, v);
147         }
148         BFS();
149         while (q--)
150         {
151             solve();
152         }
153     }
154 }
155 
156 int main()
157 {
158 #ifdef LOCAL_JUDGE
159     freopen("Text.txt", "r", stdin);
160 #endif // LOCAL_JUDGE
161 
162     RUN();
163 
164 #ifdef LOCAL_JUDGE
165     fclose(stdin);
166 #endif // LOCAL_JUDGE
167     return 0;
168 }
View Code

 

 

Network POJ - 3417

题意:给出一棵树和一些非树边,你可以选择破坏一条树边以及一条非树边,问有多少种方式可以破坏这棵树。

思路:

对于每条非树边$u-v$都可以形成一个$u-LCA_{u, v}-v-u$的环,如果破坏这个这个环则只能选择环上一个树边以及新加入的非树边。

如果某条树边被多个环覆盖那么无法通过破坏这条边以及非树边来破坏整棵树。

如果某条树边没有被环覆盖那么可以通过破坏这条树边以及任意一条非树边来破坏整棵树。

最后可以通过$LCA$以及树上差分(前缀和?)来优化求出每条树边被多少个环覆盖。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<queue>
  7 
  8 using namespace std;
  9 
 10 typedef long long ll;
 11 const int maxn = 1e6 + 10;
 12 const int DEG = 20;
 13 
 14 struct Edge {
 15     int to, nxt;
 16     Edge() {}
 17     Edge(int to, int nxt) :to(to), nxt(nxt) {}
 18 }edge[maxn << 1];
 19 
 20 int head[maxn], tot;
 21 
 22 int dis[maxn];
 23 
 24 void addedge(int u, int v)
 25 {
 26     edge[tot] = Edge(v, head[u]);
 27     head[u] = tot++;
 28 }
 29 
 30 void init()
 31 {
 32     memset(head, -1, sizeof head);
 33     tot = 0;
 34 }
 35 
 36 int fa[maxn][DEG];
 37 int deg[maxn];
 38 
 39 void BFS(int root)
 40 {
 41     queue<int>q;
 42     deg[root] = 0;
 43     fa[root][0] = root;
 44     q.push(root);
 45     while (!q.empty())
 46     {
 47         int tmp = q.front();
 48         q.pop();
 49         for (int i = 1; i < DEG; ++i)
 50         {
 51             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
 52         }
 53         for (int i = head[tmp]; i != -1; i = edge[i].nxt)
 54         {
 55             int v = edge[i].to;
 56             if (v == fa[tmp][0]) continue;
 57             deg[v] = deg[tmp] + 1;
 58             fa[v][0] = tmp;
 59             q.push(v);
 60         }
 61     }
 62 }
 63 
 64 int LCA(int u, int v)
 65 {
 66     if (deg[u] > deg[v]) swap(u, v);
 67     int hu = deg[u];
 68     int hv = deg[v];
 69     int tu = u, tv = v;
 70     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
 71     {
 72         if (det & 1)
 73         {
 74             tv = fa[tv][i];
 75         }
 76     }
 77     if (tu == tv) return tu;
 78     for (int i = DEG - 1; i >= 0; --i)
 79     {
 80         if (fa[tu][i] == fa[tv][i])
 81             continue;
 82         tu = fa[tu][i];
 83         tv = fa[tv][i];
 84     }
 85     return fa[tu][0];
 86 }
 87 
 88 int n, m;
 89 ll arr[maxn];
 90 
 91 void DFS(int u, int pre)
 92 {
 93     for (int i = head[u]; ~i; i = edge[i].nxt)
 94     {
 95         int v = edge[i].to;
 96         if (v == pre) continue;
 97         DFS(v, u);
 98         arr[u] += arr[v];
 99     }
100 }
101 
102 void RUN()
103 {
104     while (~scanf("%d %d", &n, &m))
105     {
106         init();
107         memset(arr, 0, sizeof arr);
108         for (int i = 1; i < n; ++i)
109         {
110             int u, v;
111             scanf("%d %d", &u, &v);
112             addedge(u, v);
113             addedge(v, u);
114         }
115         BFS(1);
116         for (int i = 1; i <= m; ++i)
117         {
118             int u, v;
119             scanf("%d %d", &u, &v);
120             arr[u]++;
121             arr[v]++;
122             arr[LCA(u, v)] -= 2;
123         }
124         DFS(1, -1);
125         ll ans = 0;
126         for (int i = 2; i <= n; ++i)
127         {
128             if (!arr[i])
129             {
130                 ans += m;
131             }
132             else if (arr[i] == 1)
133             {
134                 ans++;
135             }
136         }
137         printf("%lld\n", ans);
138     }
139 }
140 
141 int main()
142 {
143 #ifdef LOCAL_JUDGE
144     freopen("Text.txt", "r", stdin);
145 #endif // LOCAL_JUDGE
146 
147     RUN();
148 
149 #ifdef LOCAL_JUDGE
150     fclose(stdin);
151 #endif // LOCAL_JUDGE
152 
153     return 0;
154 }
View Code

 

Imperial roads UVALive - 8196

题意:给出一张图,然后询问给出一条边,求有这条边的最小生成树的权值和。

思路:

先求最小生成树,然后询问的边如果在最小生成树里面那么就是原来的最小生成树的权值和。

否则在原来的最小生成树里面的加入一条边,形成个环,然后去掉这个环里面除了加入的边之外的边权最大的边即可。

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 
  7 const int maxn = 2e5 + 10;
  8 const int DEG = 20;
  9 
 10 int n, m;
 11 
 12 struct node {
 13     int u, v;
 14     ll w;
 15     node() {}
 16     node(int u, int v, ll w) :u(u), v(v), w(w) {}
 17     inline bool operator < (const node &b)const
 18     {
 19         return w < b.w;
 20     }
 21 };
 22 
 23 struct Edge {
 24     int to;
 25     int nxt;
 26     ll w;
 27     Edge() {}
 28     Edge(int to, int nxt, ll w) :to(to), nxt(nxt), w(w) {}
 29 }edge[maxn << 1];
 30 
 31 int dis[maxn][DEG];
 32 bool inMST[maxn << 1];
 33 int head[maxn];
 34 int tot;
 35 int father[maxn];
 36 vector<node>G;
 37 int cnt;
 38 map<pair<int, int>, int>mp;
 39 
 40 void addedge(int u, int v, ll w)
 41 {
 42     edge[tot] = Edge(v, head[u], w); head[u] = tot++;
 43     edge[tot] = Edge(u, head[v], w); head[v] = tot++;
 44 }
 45 
 46 void Init()
 47 {
 48     G.clear();
 49     cnt = 0;
 50     tot = 0;
 51     memset(dis, 0, sizeof dis);
 52     memset(head, -1, sizeof head);
 53     for (int i = 1; i <= n; ++i)
 54     {
 55         father[i] = i;
 56     }
 57 }
 58 
 59 int find(int x)
 60 {
 61     return x == father[x] ? father[x] : father[x] = find(father[x]);
 62 }
 63 
 64 void mix(int x, int y)
 65 {
 66     x = find(x);
 67     y = find(y);
 68     if (x != y)
 69     {
 70         father[x] = y;
 71     }
 72 }
 73 
 74 bool same(int x, int y)
 75 {
 76     return find(x) == find(y);
 77 }
 78 
 79 ll MST()
 80 {
 81     mp.clear();
 82     ll res = 0;
 83     sort(G.begin(), G.end());
 84     memset(inMST, false, sizeof inMST);
 85     for (auto it : G)
 86     {
 87         int u = it.u;
 88         int v = it.v;
 89         mp[make_pair(v, u)] = cnt;
 90         mp[make_pair(u, v)] = cnt++;
 91     }
 92     for (auto it : G)
 93     {
 94         int u = it.u;
 95         int v = it.v;
 96         if (same(u, v)) continue;
 97         mix(u, v);
 98         inMST[mp[make_pair(u, v)]] = true;
 99         addedge(u, v, it.w);
100         res += it.w;
101     }
102     return res;
103 }
104 
105 int fa[maxn][DEG];
106 int deg[maxn];
107 
108 void BFS(int root)
109 {
110     queue<int>q;
111     deg[root] = 0;
112     fa[root][0] = root;
113     q.push(root);
114     while (!q.empty())
115     {
116         int tmp = q.front();
117         q.pop();
118         for (int i = 1; i < DEG; ++i)
119         {
120             dis[tmp][i] = max(dis[tmp][i - 1], dis[fa[tmp][i - 1]][i - 1]);
121             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
122         }
123         for (int i = head[tmp]; ~i; i = edge[i].nxt)
124         {
125             int v = edge[i].to;
126             if (v == fa[tmp][0]) continue;
127             deg[v] = deg[tmp] + 1;
128             fa[v][0] = tmp;
129             int id = mp[make_pair(tmp, v)];
130             dis[v][0] = G[id].w;
131             q.push(v);
132         }
133     }
134 }
135 
136 int LCA(int u, int v)
137 {
138     int res = 0;
139     if (deg[u] > deg[v])
140         swap(u, v);
141     int hu = deg[u], hv = deg[v];
142     int tu = u, tv = v;
143     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
144     {
145         if (det & 1)
146         {
147             res = max(res, dis[tv][i]);
148             tv = fa[tv][i];
149         }
150     }
151     if (tu == tv) return res;
152     for (int i = DEG - 1; i >= 0; --i)
153     {
154         if (fa[tu][i] == fa[tv][i]) continue;
155         res = max(res, max(dis[tu][i], dis[tv][i]));
156         tu = fa[tu][i];
157         tv = fa[tv][i];
158     }
159     res = max(res, max(dis[tu][0], dis[tv][0]));
160     return res;
161 }
162 
163 void RUN()
164 {
165     while (~scanf("%d %d", &n, &m))
166     {
167         Init();
168         for (int i = 1; i <= m; ++i)
169         {
170             int u, v;
171             ll w;
172             scanf("%d %d %lld", &u, &v, &w);
173             G.push_back(node(u, v, w));
174         }
175         ll ans = MST();
176         BFS(1);
177         int q;
178         scanf("%d", &q);
179         while (q--)
180         {
181             int u, v;
182             scanf("%d %d", &u, &v);
183             int id = mp[make_pair(u, v)];
184             ll w = G[id].w;
185             if (inMST[id])
186             {
187                 printf("%lld\n", ans);
188             }
189             else
190             {
191                 ll res = LCA(u, v);
192                 printf("%lld\n", ans + w - res);
193             }
194         }
195     }
196 }
197 
198 int main()
199 {
200 #ifdef LOCAL_JUDGE
201     freopen("Text.txt", "r", stdin);
202 #endif // LOCAL_JUDGE
203 
204     RUN();
205 
206 #ifdef LOCAL_JUDGE
207     fclose(stdin);
208 #endif // LOCAL_JUDGE
209 
210     return 0;
211 }
View Code

 

CD操作 HDU - 4547

题意:

思路:

从$u-v$的操作数为$dis_u-dis_{LCA{u, v}}$

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 const int maxn = 1e5 + 10;
  7 const int DEG = 20;
  8 
  9 struct Edge {
 10     int to, nxt;
 11     inline Edge() {}
 12     inline Edge(int to, int nxt) :to(to), nxt(nxt) {}
 13 }edge[maxn << 1];
 14 
 15 int head[maxn], tot;
 16 
 17 map<string, int>mp;
 18 int dis[maxn];
 19 
 20 inline void addedge(int u, int v)
 21 {
 22     edge[tot] = Edge(v, head[u]);
 23     head[u] = tot++;
 24 }
 25 
 26 inline void init()
 27 {
 28     memset(head, -1, sizeof head);
 29     tot = 0;
 30 }
 31 
 32 int fa[maxn][DEG];
 33 int deg[maxn];
 34 
 35 inline void BFS(int root)
 36 {
 37     queue<int>q;
 38     deg[root] = 0;
 39     dis[root] = 0;
 40     fa[root][0] = root;
 41     q.push(root);
 42     while (!q.empty())
 43     {
 44         int tmp = q.front();
 45         q.pop();
 46         for (int i = 1; i < DEG; ++i)
 47         {
 48             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
 49         }
 50         for (int i = head[tmp]; i != -1; i = edge[i].nxt)
 51         {
 52             int v = edge[i].to;
 53             if (v == fa[tmp][0]) continue;
 54             deg[v] = deg[tmp] + 1;
 55             dis[v] = dis[tmp] + 1;
 56             fa[v][0] = tmp;
 57             q.push(v);
 58         }
 59     }
 60 }
 61 
 62 inline int LCA(int u, int v)
 63 {
 64     if (deg[u] > deg[v]) swap(u, v);
 65     int hu = deg[u];
 66     int hv = deg[v];
 67     int tu = u, tv = v;
 68     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
 69     {
 70         if (det & 1)
 71         {
 72             tv = fa[tv][i];
 73         }
 74     }
 75     if (tu == tv) return tu;
 76     for (int i = DEG - 1; i >= 0; --i)
 77     {
 78         if (fa[tu][i] == fa[tv][i])
 79             continue;
 80         tu = fa[tu][i];
 81         tv = fa[tv][i];
 82     }
 83     return fa[tu][0];
 84 }
 85 
 86 int n, m;
 87 bool flag[maxn];
 88 
 89 inline void RUN()
 90 {
 91     int t;
 92     cin >> t;
 93     while (t--)
 94     {
 95         cin >> n >> m;
 96         init();
 97         mp.clear();
 98         int cnt = 1;
 99         memset(flag, false, sizeof flag);
100         for (int i = 1; i < n; ++i)
101         {
102             string s1, s2;
103             cin >> s1 >> s2;
104             if (mp[s1] == 0)
105             {
106                 mp[s1] = cnt++;
107             }
108             if (mp[s2] == 0)
109             {
110                 mp[s2] = cnt++;
111             }
112             addedge(mp[s2], mp[s1]);
113             addedge(mp[s1], mp[s2]);
114             flag[mp[s1]] = true;
115         }
116         int root = 0;
117         for (int i = 1; i < cnt; ++i)
118         {
119             if (!flag[i])
120             {
121                 root = i;
122                 break;
123             }
124         }
125         BFS(root);
126         while (m--)
127         {
128             string s1, s2;
129             cin >> s1 >> s2;
130             int u = mp[s1];
131             int v = mp[s2];
132             int tmp = LCA(u, v);
133             int ans = dis[u] - dis[tmp];
134             if (tmp != v)
135             {
136                 ans++;
137             }
138             cout << ans << endl;
139         }
140     }
141 }
142 
143 int main()
144 {
145 #ifdef LOCAL_JUDGE
146     freopen("Text.txt", "r", stdin);
147 #endif // LOCAL_JUDGE
148 
149     RUN();
150 
151 #ifdef LOCAL_JUDGE
152     fclose(stdin);
153 #endif // LOCAL_JUDGE
154 
155     return 0;
156 }
View Code

 

Red Black Tree ZOJ - 4048

题意:有一个树,上面有红点和黑点,有边权,每个点的花费定义为它到离它最近的红点的距离,每次询问给出一些点,能够将这棵树中的一个黑点变为红点,使得这些点中的最大花费最小

思路:

二分答案,符合条件的点不管,将不符合条件的点LCA求出来,变红,然后算距离

ST表求LCA可直接过,复杂度为$O(n \cdot log_n)$。

倍增求LCA复杂度为$O(n \cdot log_n \cdot log_n)$。

倍增求LCA可先根据深度排序,当有两个不符合的点上方的红点不同时则不能通过修改一个点使得所有不符合的点都产生改变,从而剪枝。

ST表。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define N 100010
  5 #define ll long long
  6 #define INFLL 0x3f3f3f3f3f3f3f3f
  7 
  8 struct Edge
  9 {
 10     int to, nx; ll w;
 11     inline Edge() {}
 12     inline Edge(int to, int nx, ll w) : to(to), nx(nx), w(w) {}
 13 }edge[N << 1];
 14 
 15 int t, n, m, q, k;
 16 int isred[N], prered[N], head[N], arr[N], pos;
 17 int rmq[N << 1], F[N << 1], P[N], deep[N], cnt; 
 18 ll dist[N]; 
 19 
 20 inline void Init()
 21 {
 22     memset(head, -1, sizeof head); pos = 0;
 23     memset(isred, 0, sizeof isred);  deep[1] = 0;
 24 }
 25 
 26 inline void addedge(int u, int v, ll w)
 27 {
 28     edge[++pos] = Edge(v, head[u], w); head[u] = pos;
 29 }
 30 
 31 struct ST
 32 {
 33     int mm[N << 1];
 34     int dp[N << 1][20];
 35     inline void init(int n)
 36     {
 37         mm[0] = -1;
 38         for (int i = 1; i <= n; ++i)
 39         {
 40             mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
 41             dp[i][0] = i;
 42         }
 43         for (int j = 1; j <= mm[n]; ++j)
 44         {
 45             for (int i = 1; i + (1 << j) - 1 <= n; ++i)
 46             {
 47                 dp[i][j] = rmq[dp[i][j - 1]] < rmq[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1];
 48             }
 49         }
 50     }
 51     inline int query(int a, int b)
 52     {
 53         if (a > b) swap(a, b);
 54         int k = mm[b - a + 1];
 55         return rmq[dp[a][k]] <= rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] : dp[b - (1 << k) + 1][k];
 56     }
 57 }st;
 58 
 59 inline void DFS(int u, int pre, int prer)
 60 {
 61     F[++cnt] = u;
 62     rmq[cnt] = deep[u];
 63     P[u] = cnt;
 64     prered[u] = prer;  
 65     for (int it = head[u]; ~it; it = edge[it].nx)
 66     {
 67         int v = edge[it].to;
 68         if (v == pre) continue;
 69         if (isred[v]) dist[v] = 0;
 70         else dist[v] = dist[u] + edge[it].w;
 71         deep[v] = deep[u] + 1;
 72         DFS(v, u, isred[v] ? v : prer);
 73         F[++cnt] = u;
 74         rmq[cnt] = deep[u];
 75     }
 76 }
 77 
 78 inline void Lca_Init(int root, int node_num)
 79 {
 80     cnt = 0;
 81     DFS(root, root, 1);
 82     st.init(2 * node_num - 1);
 83 }
 84 
 85 inline int query_lca(int u, int v)
 86 {
 87     return F[st.query(P[u], P[v])];
 88 }
 89 
 90 vector <int> v; 
 91 inline bool check(ll mid)
 92 {
 93     v.clear();
 94     for (int i = 1; i <= k; ++i)
 95     {
 96         if (dist[arr[i]] > mid)
 97             v.emplace_back(arr[i]);
 98     }
 99     if (v.empty()) return true; 
100     int lca = v[0];
101     for (int i = 1, len = v.size(); i < len; ++i)
102         lca = query_lca(lca, v[i]);
103     if (isred[lca]) return false;  
104     for (auto it : v)
105     {
106         if (deep[lca] < deep[prered[it]]) return false; 
107         else if (dist[it] - dist[lca] > mid) return false;  
108     }
109     return true;
110 }
111 
112 inline void Run() 
113 {
114     for (scanf("%d", &t); t--; )
115     {
116         scanf("%d%d%d", &n, &m, &q); Init();
117         for (int i = 1, u; i <= m; ++i)
118         {
119             scanf("%d", &u);
120             isred[u] = 1;
121         }
122         ll w;
123         for (int i = 1, u, v; i < n; ++i)
124         {
125             scanf("%d%d%lld", &u, &v, &w);
126             addedge(u, v, w); addedge(v, u, w);
127         }
128         Lca_Init(1, n);
129         for (int qq = 1; qq <= q; ++qq)
130         {
131             scanf("%d", &k);
132             for (int i = 1; i <= k; ++i) scanf("%d", arr + i); 
133             if (k == 1)
134             {
135                 puts("0");
136                 continue;
137             }
138             ll l = 0, r = INFLL, ans; 
139             while (r - l >= 0)
140             {
141                 ll mid = (l + r) >> 1;
142                 if (check(mid))
143                 {
144                     ans = mid;
145                     r = mid - 1;
146                 }
147                 else
148                     l = mid + 1;
149             }
150             printf("%lld\n", ans);
151         }
152     }
153 }
154 
155 int main()
156 {
157     #ifdef LOCAL  
158         freopen("Test.in", "r", stdin); 
159     #endif    
160         
161     Run();
162     return 0;
163 }
View Code

倍增求LCA。

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 
  7 const int INF = 0x3f3f3f3f;
  8 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
  9 const ll MOD = (int)1e9 + 7;
 10 const int maxn = (int)1e5 + 10;
 11 
 12 const int DEG = 20;
 13 
 14 struct Edge {
 15     int to, nxt;
 16     ll w;
 17     Edge() {}
 18     Edge(int to, int nxt, ll w) :to(to), nxt(nxt), w(w) {}
 19 }edge[maxn << 1];
 20 
 21 int head[maxn], tot;
 22 int red[maxn];
 23 
 24 void addedge(int u, int v, ll w)
 25 {
 26     edge[tot] = Edge(v, head[u], w); head[u] = tot++;
 27 }
 28 
 29 void Init(int n)
 30 {
 31     for (int i = 1; i <= n; ++i)
 32     {
 33         red[i] = 0;
 34         head[i] = -1;
 35     }
 36     tot = 0;
 37 }
 38 
 39 ll dis[maxn];
 40 int fa[maxn][DEG];
 41 int deg[maxn];
 42 int pre[maxn];
 43 
 44 void BFS(int root)
 45 {
 46     queue<int>q;
 47     dis[root] = 0;
 48     deg[root] = 0;
 49     fa[root][0] = root;
 50     pre[root] = root;
 51     q.push(root);
 52     while (!q.empty())
 53     {
 54         int tmp = q.front();
 55         q.pop();
 56         for (int i = 1; i < DEG; ++i)
 57         {
 58             fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1];
 59         }
 60         for (int i = head[tmp]; ~i; i = edge[i].nxt)
 61         {
 62             int v = edge[i].to;
 63             ll w = edge[i].w;
 64             if (v == fa[tmp][0]) continue;
 65             deg[v] = deg[tmp] + 1;
 66             fa[v][0] = tmp;
 67             if (red[v])
 68             {
 69                 pre[v] = v;
 70             }
 71             else
 72             {
 73                 pre[v] = pre[tmp];
 74             }
 75             if (red[v])
 76             {
 77                 dis[v] = 0;
 78             }
 79             else
 80             {
 81                 dis[v] = dis[tmp] + w;
 82             }
 83             q.push(v);
 84         }
 85     }
 86 }
 87 
 88 int LCA(int u, int v)
 89 {
 90     if (deg[u] > deg[v]) swap(u, v);
 91     int hu = deg[u], hv = deg[v];
 92     int tu = u, tv = v;
 93     for (int det = hv - hu, i = 0; det; det >>= 1, ++i)
 94     {
 95         if (det & 1)
 96         {
 97             tv = fa[tv][i];
 98         }
 99     }
100     if (tu == tv) return tu;
101     for (int i = DEG - 1; i >= 0; --i)
102     {
103         if (fa[tu][i] == fa[tv][i]) continue;
104         tu = fa[tu][i], tv = fa[tv][i];
105     }
106     return fa[tu][0];
107 }
108 
109 int n, m, q, k;
110 int arr[maxn];
111 
112 bool cmp(int a, int b)
113 {
114     return dis[a] > dis[b];
115 }
116 
117 bool check(ll mid)
118 {
119     int root = arr[1];
120     int cnt = 0;
121     for (int i = 1; i <= k; ++i)
122     {
123         if (dis[arr[i]] > mid)
124         {
125             if (pre[root] != pre[arr[i]]) return false;
126             root = LCA(root, arr[i]);
127             cnt++;
128         }
129     }
130     if (cnt == 1 || cnt == 0) return true;
131     for (int i = 1; i <= k; ++i)
132     {
133         if (dis[arr[i]] > mid)
134         {
135             if (dis[arr[i]] - dis[root] > mid) return false;
136         }
137     }
138     return true;
139 }
140 
141 void RUN()
142 {
143     int t;
144     scanf("%d", &t);
145     while (t--)
146     {
147         scanf("%d %d %d", &n, &m, &q);
148         Init(n);
149         for (int i = 1; i <= m; ++i)
150         {
151             int u;
152             scanf("%d", &u);
153             red[u] = 1;
154         }
155         for (int i = 1; i < n; ++i)
156         {
157             int u, v;
158             ll w;
159             scanf("%d %d %lld", &u, &v, &w);
160             addedge(u, v, w);
161             addedge(v, u, w);
162         }
163         BFS(1);
164         while (q--)
165         {
166             scanf("%d", &k);
167             for (int i = 1; i <= k; ++i)
168             {
169                 scanf("%d", arr + i);
170             }
171             if (k == 1)
172             {
173                 puts("0");
174                 continue;
175             }
176             sort(arr + 1, arr + 1 + k, cmp);
177             ll l = 0;
178             ll r = INFLL;
179             ll ans = 0;
180             while (r - l >= 0)
181             {
182                 ll mid = (r + l) >> 1;
183                 if (check(mid))
184                 {
185                     r = mid - 1;
186                     ans = mid;
187                 }
188                 else
189                 {
190                     l = mid + 1;
191                 }
192             }
193             printf("%lld\n", ans);
194         }
195     }
196 }
197 
198 int main()
199 {
200 #ifdef LOCAL_JUDGE
201     freopen("Text.txt", "r", stdin);
202 #endif // LOCAL_JUDGE
203 
204     RUN();
205 
206 #ifdef LOCAL_JUDGE
207     fclose(stdin);
208 #endif // LOCAL_JUDGE
209     return 0;
210 }
View Code

 

posted @ 2019-02-11 11:22  Dup4  阅读(265)  评论(0编辑  收藏  举报