Vijos上的三道LCA: 1427, 1460, 1710

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 }
View Code

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 }
View Code

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 }
View Code

 

原文地址:https://www.cnblogs.com/jimzeng/p/Vijos-LCA.html