zoukankan      html  css  js  c++  java
  • 【洛谷】【lca+树上差分】P3258 [JLOI2014]松鼠的新家

    【题目描述:】

    松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n(2 ≤ n ≤ 300000)个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。

    松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。

    维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。

    因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

    【输入格式:】 

    第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an

    接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

    【输出格式:】

    一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。

    输入样例#15
    1 4 5 3 2
    1 2
    2 4
    2 3
    4 5
    输出样例#11
    2
    1
    2
    1
    输入输出样例

    【算法分析:】

    根据小熊维尼走的路径记录每个点走过的次数,就是需要放的糖果数目

    从点i走到点j, 可以看做:从i走到lca(i, j)再走到j是最短的路径。

    而如何把i -> lca, j -> lca的点全部自增1呢?

    可以用树上差分来维护,设定一个一维数组cha

    对于从i到j的一条路径,

    cha[i]++; cha[j]++;
    cha[lca(i, j)]--;
    cha[f[lca(i, j)][0]]--;//点i, j最近公共祖先的父节点

    然后从根节点开始dfs这棵树,对cha数组做一遍前缀和

    最后对所有既是起点也是重点的点的经过次数-1.

    【代码:】

     1 //P3258 [JLOI2014]松鼠的新家
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 using namespace std;
     6 
     7 const int MAXN = 300000 + 1;
     8 const int K = 29 + 1;
     9 
    10 int n, a[MAXN], ans[MAXN];
    11 int cha[MAXN];
    12 int deep[MAXN], f[MAXN][K];
    13 int edge_num, head[MAXN];
    14 struct Edge {
    15     int to, next;
    16 }h[MAXN << 1];
    17 
    18 inline int read() {
    19     int x = 0, f = 1; char ch = getchar();
    20     while(ch < '0' || ch > '9') {
    21         if(ch == '-') f = -1;
    22         ch = getchar();
    23     }
    24     while(ch >= '0' && ch <= '9')
    25         x = (x << 3) + (x << 1) + ch - 48, ch = getchar();
    26     return x * f;
    27 }
    28 
    29 inline void Add(int from, int to) {
    30     h[++edge_num].to = to;
    31     h[edge_num].next = head[from];
    32     head[from] = edge_num;
    33 }
    34 
    35 void build(int u) {
    36     for(int i = head[u]; i != -1; i = h[i].next) {
    37         if(!deep[h[i].to]) {
    38             deep[h[i].to] = deep[u] + 1;
    39             f[h[i].to][0] = u;
    40             build(h[i].to);
    41         }
    42     }
    43 }
    44 
    45 inline void fill() {
    46     for(int j = 1; j < K; ++j)
    47     for(int i = 1; i <= n; ++i)
    48         f[i][j] = f[f[i][j - 1]][j - 1];
    49 }
    50 
    51 int lca(int a, int b) {
    52     if(deep[a] > deep[b])
    53         swap(a, b);
    54     for(int i = K - 1; i >= 0; --i)
    55         if(deep[f[b][i]] >= deep[a]) b = f[b][i];
    56     if(a == b) return a;
    57     for(int i = K - 1; i >= 0; --i) {
    58         if(f[b][i] != f[a][i]) {
    59             a = f[a][i], b = f[b][i];
    60         }
    61     }
    62     return f[b][0];
    63 }
    64 
    65 void dfs(int u) {
    66     for(int i = head[u]; i != -1; i = h[i].next) {
    67         if(h[i].to == f[u][0]) continue;
    68         dfs(h[i].to); 
    69         cha[u] += cha[h[i].to];
    70     }
    71 }
    72 
    73 int main() {
    74     memset(head, -1, sizeof(head));
    75     n = read();
    76     for(int i = 1; i <= n; ++i) a[i] = read();
    77     for(int i = 1; i < n; ++i) {
    78         int x = read(), y = read();
    79         Add(x, y);
    80         Add(y, x);
    81     }
    82     deep[a[n]] = 1;
    83     build(a[n]);
    84     fill();
    85     for(int i = 2; i <= n; ++i) {
    86         int com = lca(a[i], a[i - 1]);
    87         ++cha[a[i]], ++cha[a[i - 1]];
    88         --cha[com], --cha[f[com][0]];
    89     }
    90     dfs(a[n]);
    91     for(int i = 2; i <= n; ++i)
    92         --cha[a[i]];
    93     for(int i = 1; i <= n; ++i)
    94         printf("%d
    ", cha[i]);
    95 }
  • 相关阅读:
    一些集群操作以及问题查询
    .a 文件 和 so 文件
    KNN算法
    opendir函数和readdir函数内涵及用法
    tps 和 qps的区别
    Git使用(积累一些常用的命令)
    MurmurHash
    HyperLogLog
    MySQL主从不生效且无错误
    正则表达式与SQL
  • 原文地址:https://www.cnblogs.com/devilk-sjj/p/9050195.html
Copyright © 2011-2022 走看看