• 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

     

  • 相关阅读:
    python-输入不定长参数函数传值
    排球计分规则
    我与计算机
    会议总结
    典型用户、用户故事和用户场景
    排球比赛计分规则功能说明书
    我与计算机
    黑马程序员——【Java基础】——String、StringBuffer和基本数据包装类
    黑马程序员——【Java基础】——多线程
    黑马程序员——【Java基础】——面向对象(二)异常机制、包(Package)
  • 原文地址:https://www.cnblogs.com/jimzeng/p/Vijos-LCA.html
Copyright © 2020-2023  润新知