zoukankan      html  css  js  c++  java
  • 洛谷P3258 [JLOI2014]松鼠的新家

    题目描述

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

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

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

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

    输入输出格式

    输入格式:

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

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    5
    1 4 5 3 2
    1 2
    2 4
    2 3
    4 5
    输出样例#1: 复制
    1
    2
    1
    2
    1

    说明

    2<= n <=300000

    (这张图片转的23333)

    /*
        真不知道这么简单的题目怎么紫的23333
        还是树上差分的点差分 和最大流那题基本一样
        要注意的是因为求解时每个除了第一个和最后一个a[i]会多用一次
        所以最后的结果这些a[i]要-- 然后a[n]那里没饭吃 也要--
        其他真的和最大流没有区别了TAT
    */
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int MAXN = 300010;
    
    int deep[MAXN],f[MAXN][25],lg[MAXN],head[MAXN],cnt;
    int n,m,s,ppt[MAXN],a[MAXN];
    
    struct node{
        int to,pre;
    }G[MAXN<<2];
    
    void add(int from,int to){
        G[++cnt].to = to;
        G[cnt].pre = head[from];
        head[from] = cnt;
    }
    
    inline int read() {
         int x = 0,m = 1;
         char ch;
         while(ch < '0' || ch > '9')  {if(ch == '-') m = -1;ch = getchar();}
         while(ch >= '0' && ch <= '9'){x = x*10+ch-'0';ch=getchar();}
         return m * x;
     }
    
    inline void dfs1(int u)
    {
        for(int i = head[u];i;i = G[i].pre)
        {
            int v = G[i].to;
            if(v != f[u][0])
            {
                f[v][0] = u;
                deep[v] = deep[u] + 1;
                dfs1(v);
            }
        }
    }
    
    inline int lca(int u,int v)
    {
        if(deep[u] < deep[v]) swap(u,v);
        int dis = deep[u] - deep[v];
        for(register int i = 0;i <= lg[n];i++)
        {
            if((1 << i) & dis) u = f[u][i];
        }
        if(u == v) return u;
        for(register int i = lg[deep[u]];i >= 0;i--)
        {
            if(f[u][i] != f[v][i])
            {
                u = f[u][i];v = f[v][i];
            }
        }
        return f[u][0];
    }
    
    inline void init()
    {
        for(register int i = 1;i <= n;i++)
        {
            lg[i] = lg[i-1] + (1 << lg[i-1] + 1 == i);
        }
        for(register int j = 1;j <= lg[n];j++)
        {
            for(register int i = 1;i <= n;i++)
            {
                if(f[i][j-1] != -1)
                f[i][j] = f[f[i][j-1]][j-1];
            }
        }
    }
    
    inline void dfs2(int u,int fa){
        for(int i = head[u];i;i = G[i].pre){
            int v = G[i].to;
            if(v == fa) continue;
            dfs2(v,u);
            ppt[u] += ppt[v];
        }
    }
    
    int main()
    {
        int x,y;
        n = read();
        for(register int i = 1;i <= n;i++){
            a[i] = read();
        }
        for(register int i = 1;i <= n-1;i++)
        {
            x = read();y = read();
            add(x,y);add(y,x);
        }
        dfs1(1);
        init();
        for(int i = 1;i <= n-1;i++){
            x = a[i];y = a[i+1];//可以看到这里多算了一次
            int Lca = lca(x,y);
            ppt[x]++,ppt[y]++,ppt[Lca]--,ppt[f[Lca][0]]--;//还是树上差分的操作
        }
        dfs2(1,0);
        for(int i = 2;i <= n;i++) ppt[a[i]]--;//一定要注意这里--
        for(int i = 1;i <= n;i++){
            printf("%d
    ",ppt[i]);
        }
        return 0;
    }
  • 相关阅读:
    oracle之三 自动任务调度
    oracle之三资源管理
    oracle之三rman 维护
    oracle之三目录库和辅助库
    oracle之三rman 不完全恢复
    oracle之三rman 备份
    oracle之三rman 完全恢复
    oracle之三RMAN概述
    oracle之三闪回flashback
    Vimium
  • 原文地址:https://www.cnblogs.com/bryce02/p/9897259.html
Copyright © 2011-2022 走看看