标签:
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\n",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\n",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\n%I64d\n",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\n",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 }
Vijos上的三道LCA: 1427, 1460, 1710
标签:
原文地址:http://www.cnblogs.com/jimzeng/p/Vijos-LCA.html