zoukankan      html  css  js  c++  java
  • [BAOJ3631]松鼠的新家

    松鼠的新家

    题目描述

    松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。
    可是这样会导致**重复走很多房间,懒惰的**不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。**是个馋家伙,立马就答应了。
    现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。

    输入

    第一行一个整数n,表示房间个数
    第二行n个整数,依次描述a1-an
    接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

    输出

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

    样例输入

    5
    1 4 5 3 2
    1 2
    2 4
    2 3
    4 5

    样例输出

    1
    2
    1
    2
    1

    提示

    2<= n <=300000

    据说是个树链剖分的模板题,可惜,自己不行,字符串都没打完,就没看过树链剖分,就只能靠学过的东西了。很显然这就是个LCA,找到LCA,把两个点到LCA路径上的点都加一就对了,不过这么说LCA会加两次要减一,但是很显然,就算用树上倍增找到LCA,沿路径跳父亲加一也会超时,然后就出现了一个不算特别神奇的神奇的优化,差分思想。

    这玩意在学树状数组的时候就学过,当时没整明白,还各种博客的看了好久,才懂了原理,然而并没有什么卵用,换个地方就废了,自己压根就想不到,学过的没办法灵活的根据自己的需要进行修改使用,学的东西死板。

    这道题有个坑就是它没根没爹,所以就需要前向星建双向边,那么为了防止死循环就需要标记已经搜索过的边,双向边的话根就爱谁谁了,怎么着建出来的树都是合法的,注意到这些之后就正常的建树,查找LCA就行了(树上倍增),注意好细节就没问题,然后就到差分出场的时候了,怎么差分呢,算是利用树,一直向上传标记吧,那么就需要保证上传的时候只影响从该点到LCA路径上经过的点,把+1传过去,并且LCA只加一次,这么想的话只要在这两个点上+1,把+1标记上传,那路上经过的点就都会得到+1标记,并+1,这时候LCA加两次的问题就出现了,那一个-1就会抵消掉多加的一,这时候路径上的点就都搞定了,可是LCA上加一的点还会传给它的父亲,那同理给他的父亲也-1这件事情就完美解决了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstring>
     5 #define maxn 300050
     6 using namespace std;
     7 struct shu{
     8     int zhong,qian;
     9 }qxx[2*maxn];
    10 int n,js,m;
    11 int a[maxn],head[maxn],tg[maxn],deep[maxn],pd[maxn];
    12 int f[maxn][30];
    13 void add(int u,int v)
    14 {
    15     qxx[++js].zhong=v;
    16     qxx[js].qian=head[u];
    17     head[u]=js;
    18     return ;
    19 }
    20 void dfsf(int x)
    21 {
    22     pd[x]=1;
    23     for(int i=head[x];i;i=qxx[i].qian)
    24     {
    25         int ls=qxx[i].zhong;
    26         if(pd[ls]==0)
    27         {
    28             deep[ls]=deep[x]+1;
    29             f[ls][0]=x;
    30             for(int j=1;j<=m;++j)
    31                 f[ls][j]=f[f[ls][j-1]][j-1];
    32             dfsf(ls);
    33         }
    34     }
    35     return ;
    36 }
    37 int lca(int x,int y)
    38 {
    39     if(deep[x]>deep[y])  swap(x,y);
    40     for(int i=m;i>=0;--i)
    41         if(deep[f[y][i]]>=deep[x])  y=f[y][i];
    42     if(x==y)  return x;
    43     for(int i=m;i>=0;--i)
    44         if(f[x][i]!=f[y][i])
    45         {
    46             x=f[x][i];
    47             y=f[y][i];
    48         }
    49     return f[x][0];
    50 }
    51 void dfs(int x)
    52 {
    53     pd[x]=1;
    54     for(int i=head[x];i;i=qxx[i].qian)
    55     {
    56         int ls=qxx[i].zhong;
    57         if(pd[ls]==0)
    58         {
    59             dfs(ls);
    60             tg[x]+=tg[ls];
    61         }
    62     }
    63     return ;
    64 }
    65 int main()
    66 {
    67     scanf("%d",&n);  m=(int)(log(n)/log(2))+2;
    68     for(int i=1;i<=n;++i)  scanf("%d",&a[i]);
    69     for(int i=1;i<n;++i)
    70     {
    71         int x,y;  scanf("%d%d",&x,&y);
    72         add(x,y);  add(y,x);
    73     }
    74     deep[1]=1;  dfsf(1);
    75     memset(pd,0,sizeof(pd));
    76     for(int i=1;i<n;++i)
    77     {
    78         int ls=lca(a[i],a[i+1]);
    79         tg[a[i]]+=1;  tg[a[i+1]]+=1;
    80         tg[ls]-=1;  tg[f[ls][0]]-=1;
    81     }
    82     dfs(1);
    83     tg[a[1]]++;
    84     for(int i=1;i<=n;++i)  printf("%d
    ",tg[i]-1);
    85     return 0;
    86 }
    View Code
  • 相关阅读:
    4.eureka控制台显示注册的服务IP以及心跳间隔和服务续约时间设置
    3.eureka高可用
    2.注册中心eureka
    1.模拟微服务环境
    oracle视图
    oracle分页查询与Rownum
    IDEA实用配置
    在django使用websocket
    dockerfile镜像设置中文
    python框架day01
  • 原文地址:https://www.cnblogs.com/hzjuruo/p/11296007.html
Copyright © 2011-2022 走看看