Vijos上一共有三道标记为LCA的题目:P1427机密信息,P1460拉力赛,P1710Mrw的工资计划。
首先是P1427机密信息。考虑到只需要求一次LCA,数据范围也不大,直接暴力解决,只是分类讨论有点麻烦。
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 #include <queue>
6 #define rep(i,l,r) for(int i=l; i<=r; i++)
7 #define clr(x,y) memset(x,y,sizeof(x))
8 #define travel(x) for(int i=last[x]; i; i=edge[i].pre)
9 typedef long long ll;
10 using namespace std;
11 const int INF = 0x3f3f3f3f;
12 const int maxn = 10010;
13 struct Edge{
14 int pre,to,cost;
15 }edge[maxn];
16 int n,s,t,x,y,tot=0,root,totaltime=0,d[maxn],last[maxn],depth[maxn],father[maxn],countt[maxn],timee[maxn];
17 string str;
18 inline int read(){
19 int ans = 0, f = 1;
20 char c = getchar();
21 while (!isdigit(c)){
22 if (c == '-') f = -1;
23 c = getchar();
24 }
25 while (isdigit(c)){
26 ans = ans * 10 + c - '0';
27 c = getchar();
28 }
29 return ans * f;
30 }
31 inline void addedge(int x,int y,int z){
32 edge[++tot].pre = last[x];
33 edge[tot].to = y;
34 edge[tot].cost = z;
35 last[x] = tot;
36 }
37 void dfs(int x){
38 travel(x){
39 depth[edge[i].to] = depth[x] + 1;
40 timee[edge[i].to] = timee[x] + countt[edge[i].to];
41 d[edge[i].to] = d[x] + edge[i].cost;
42 dfs(edge[i].to);
43 }
44 }
45 int lca(int x,int y){
46 if (depth[x] < depth[y]) swap(x,y);
47 while (depth[x] != depth[y]) x = father[x];
48 while (x != y){
49 x = father[x]; y = father[y];
50 }
51 return x;
52 }
53 void solve(){
54 int l = lca(s,t);
55 int res = d[s] + d[t] - d[l] - d[father[l]];
56 printf("%d
",res);
57 if (l != s && l != t) totaltime = timee[father[s]] + timee[father[t]] - timee[l] - timee[father[l]];
58 else if (l == s) totaltime = timee[father[t]] - timee[s];
59 else if (l == t) totaltime = timee[father[s]] - timee[father[t]];
60 printf("%d
",totaltime);
61 }
62 int main(){
63 n = read(); s = read(); t = read(); clr(countt,0); clr(last,0);
64 rep(i,1,n){
65 x = read(); y = read(); cin >> str;
66 addedge(y,x,str.length());
67 father[x] = y; countt[y]++;
68 }
69 d[0] = 0; dfs(0);
70 solve();
71 return 0;
72 }
P1460拉力赛,非常裸的一道倍增求LCA。
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 #include <queue>
6 #define rep(i,l,r) for (int i=l; i<=r; i++)
7 #define clr(x,y) memset(x,y,sizeof(x))
8 #define travel(x) for (int i=last[x]; i; i=edge[i].pre)
9 typedef long long ll;
10 using namespace std;
11 const int INF = 0x3f3f3f3f;
12 const int maxn = 10010;
13 struct Edge{
14 ll pre,toward,cost;
15 }edge[maxn<<1];
16 ll n,m,x,y,z,now,tot=0,total,totald,father[maxn],last[maxn],fa[maxn][16],depth[maxn],d[maxn];
17 bool vis[maxn];
18 inline ll read(){
19 int ans = 0, f = 1;
20 char c = getchar();
21 while (!isdigit(c)){
22 if (c== '-') f = -1;
23 c = getchar();
24 }
25 while (isdigit(c)){
26 ans = ans * 10 + c - '0';
27 c = getchar();
28 }
29 return ans * f;
30 }
31 inline void addedge(ll x,ll y,ll z){
32 edge[++tot].pre = last[x];
33 edge[tot].toward = y;
34 edge[tot].cost = z;
35 last[x] = tot;
36 }
37 void bfs(){
38 queue <ll> q; clr(vis,0);
39 q.push(1); depth[1] = 0; d[1] = 0;
40 while (!q.empty()){
41 now = q.front();
42 q.pop();
43 if (vis[now]) continue;
44 vis[now] = 1;
45 rep(i,1,16){
46 if (depth[now] < (1 << i)) break;
47 fa[now][i] = fa[fa[now][i-1]][i-1];
48 }
49 travel(now){
50 if (!vis[edge[i].toward]){
51 depth[edge[i].toward] = depth[now] + 1;
52 d[edge[i].toward] = d[now] + edge[i].cost;
53 fa[edge[i].toward][0] = now;
54 q.push(edge[i].toward);
55 }
56 }
57 }
58 }
59 ll lca(ll x,ll y){
60 if (depth[x] < depth[y]) swap(x,y);
61 int t = depth[x] - depth[y];
62 rep(i,0,16) if (t & (1 << i)) x = fa[x][i];
63 for (int i=16; i>=0; i--){
64 if (fa[x][i] != fa[y][i]){
65 x = fa[x][i];
66 y = fa[y][i];
67 }
68 }
69 if (x == y) return x;
70 return fa[x][0];
71 }
72 int main(){
73 n = read(); m = read();
74 rep(i,1,n-1){
75 x = read(); y = read(); z = read();
76 addedge(x,y,z); addedge(y,x,z);
77 }
78 bfs();
79 rep(i,1,m){
80 x = read(); y = read();
81 if (lca(x,y) == x) total++, totald += d[y] - d[x];
82 }
83 printf("%I64d
%I64d
",total,totald);
84 return 0;
85 }
P1710Mrw的工资计划,倍增LCA加树状数组。
题目询问奇数层与偶数层的工资之差的绝对值,将奇数层的工资存为正数,将偶数层存为负数,然后用树状数组记录每一层的增加值,计算时加上即可。
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 #include <queue>
6 #define rep(i,l,r) for(int i=l; i<=r; i++)
7 #define clr(x,y) memset(x,y,sizeof(x))
8 #define travel(x) for(int i=last[x]; i; i=edge[i].pre)
9 using namespace std;
10 const int INF = 0x3f3f3f3f;
11 const int maxn = 20010;
12 struct Edge{
13 int pre,to;
14 }edge[maxn];
15 int n,lv,tot=0,t,q,x,y,boss,maxdep=-1,last[maxn],tree[maxn],sum[maxn],pay[maxn],fa[maxn][14],depth[maxn];
16 char ch;
17 bool vis[maxn];
18 inline int read(){
19 int ans = 0, f = 1;
20 char c = getchar();
21 while (!isdigit(c)){
22 if (c == '-') f = -1;
23 c = getchar();
24 }
25 while (isdigit(c)){
26 ans = ans * 10 + c - '0';
27 c = getchar();
28 }
29 return ans * f;
30 }
31 inline int lowbit(int x){
32 return x & (-x);
33 }
34 inline void addedge(int x,int y){
35 edge[++tot].pre = last[x];
36 edge[tot].to = y;
37 last[x] = tot;
38 }
39 void add(int x,int t){
40 for(int i=x; i<=maxdep; i+=lowbit(i))
41 tree[i] += t;
42 }
43 int query(int x){
44 int ret = 0;
45 for(int i=x; i; i-=lowbit(i))
46 ret += tree[i];
47 return ret;
48 }
49 void dfs(int x){
50 vis[x] = 1;
51 rep(i,1,13){
52 if (depth[x] < (1 << i)) break;
53 fa[x][i] = fa[fa[x][i-1]][i-1];
54 }
55 travel(x){
56 if (vis[edge[i].to]) continue;
57 vis[edge[i].to] = 1;
58 depth[edge[i].to] = depth[x] + 1;
59 if (!(depth[edge[i].to] & 1)) pay[edge[i].to] = -pay[edge[i].to];
60 sum[edge[i].to] = sum[x] + pay[edge[i].to];
61 maxdep = max(maxdep,depth[edge[i].to]);
62 fa[edge[i].to][0] = x;
63 dfs(edge[i].to);
64 }
65 }
66 int lca(int x,int y){
67 if (depth[x] < depth[y]) swap(x,y);
68 int t = depth[x] - depth[y];
69 rep(i,0,13) if (t & (1 << i)) x = fa[x][i];
70 for(int i=13; i>=0; i--) if (fa[x][i] != fa[y][i]){
71 x = fa[x][i]; y = fa[y][i];
72 }
73 if (x == y) return x; return fa[x][0];
74 }
75 int main(){
76 n = read(); q = read(); clr(last,0);
77 rep(i,1,n) pay[i] = read();
78 rep(i,1,n){
79 x = read();
80 if (x == -1) boss = i;
81 else addedge(x,i);
82 }
83 clr(vis,0); depth[boss] = 1; dfs(boss); clr(tree,0);
84 rep(i,1,q){
85 scanf("%c",&ch);
86 if (ch == 'M'){
87 lv = read(); t = read();
88 if (lv & 1) add(lv,t); else add(lv,(-t));
89 }
90 else{
91 x = read(); y = read();
92 int l = lca(x,y);
93 printf("%d
",abs(sum[x] + sum[y] - (sum[l] << 1) + pay[l] + query(depth[x]) + query(depth[y])
94 - query(depth[l]) - query(depth[l] - 1)));
95 }
96 }
97 return 0;
98 }