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

    Description

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

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

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

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

    Input

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

    Output

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

    Sample Input

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

    Sample Output

    1
    2
    1
    2
    1

    Hint

    2<= n <=300000

    题解

    裸的树上差分。

    我们将一条路径如$u->v$,

    我们需要将标记数组:

    $$cnt[u]++,cnt[v]++,cnt[lca(u,v)]--,cnt[fa[lca(u,v)][0]]--$$

    最后上传标记即可,正确性可以画图推一下。

    但注意由于这样做会将每个点重复计算一次(上一条路径的结尾,这一条路径的起始)

    我们需要将每个点点权再$-1$,

    注意由于第一条路径起始点是要计算的,我们还要加回来。

      1 #include<set>
      2 #include<map>
      3 #include<ctime>
      4 #include<cmath>
      5 #include<queue>
      6 #include<stack>
      7 #include<vector>
      8 #include<cstdio>
      9 #include<string>
     10 #include<cstring>
     11 #include<cstdlib>
     12 #include<iostream>
     13 #include<algorithm>
     14 #define LL long long
     15 #define Max(a,b) ((a)>(b) ? (a):(b))
     16 #define Min(a,b) ((a)<(b) ? (a):(b))
     17 using namespace std;
     18 const int N=300000;
     19 
     20 int n,u,v,lim;
     21 struct tt
     22 {
     23     int to,next;
     24 }edge[N*2+5];
     25 int path[N+5],top;
     26 void Add(int u,int v);
     27 int a[N+5];
     28 
     29 int dep[N+5],fa[N+5][20];
     30 void Dfs(int r,int depth);
     31 void RMQ();
     32 int lca(int a,int b);
     33 
     34 int cnt[N+5];
     35 void Dfs2(int r);
     36 
     37 int main()
     38 {
     39     scanf("%d",&n);
     40     lim=log(n)/log(2);
     41     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
     42     for (int i=1;i<n;i++)
     43     {
     44       scanf("%d%d",&u,&v);
     45       Add(u,v);
     46       Add(v,u);
     47     }
     48     Dfs(1,1);
     49     RMQ();
     50     for (int i=1;i<n;i++)
     51     {
     52       int w=lca(a[i],a[i+1]);
     53       cnt[a[i]]++,cnt[a[i+1]]++,cnt[w]--,cnt[fa[w][0]]--;
     54     }
     55     Dfs2(1);
     56     cnt[a[1]]++;
     57     for (int i=1;i<=n;i++) printf("%d
    ",cnt[i]-1);
     58     return 0;
     59 }
     60 
     61 void Add(int u,int v)
     62 {
     63     edge[++top].to=v;
     64     edge[top].next=path[u];
     65     path[u]=top;
     66 }
     67 void Dfs(int r,int depth)
     68 {
     69     dep[r]=depth;
     70     for (int i=path[r];i;i=edge[i].next)
     71       if (!dep[edge[i].to])
     72       {
     73           fa[edge[i].to][0]=r;
     74           Dfs(edge[i].to,depth+1);
     75       }
     76 }
     77 void RMQ()
     78 {
     79     for (int t=1;t<=lim;t++)
     80       for (int i=1;i<=n;i++)
     81           fa[i][t]=fa[fa[i][t-1]][t-1];
     82 }
     83 int lca(int a,int b)
     84 {
     85     if (dep[a]<dep[b]) swap(a,b);
     86     for (int i=lim;i>=0;i--) if (dep[fa[a][i]]>=dep[b]) a=fa[a][i];
     87     if (a!=b)
     88     {
     89       for (int i=lim;i>=0;i--) if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
     90       a=fa[a][0],b=fa[b][0];
     91     }
     92     return a;
     93 }
     94 void Dfs2(int r)
     95 {
     96     for (int i=path[r];i;i=edge[i].next)
     97     if (edge[i].to!=fa[r][0])
     98     {
     99         Dfs2(edge[i].to);
    100         cnt[r]+=cnt[edge[i].to];
    101     }
    102 }
  • 相关阅读:
    保存ADO的记录集为XML文件
    [C++] Undefined reference to vtable
    Csdn博客的一个bug
    深入解析ATL(第二版ATL8.0)(1.111.13节)
    不同操作系统下记事本的换行符号
    dom4j学习总结(一)
    关于firefox的copy/paste的问题
    php URL编码解码函数
    php连接MySQL数据库的一些问题
    使用 jQuery progressBar 做文件上传的进度条指示
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7449095.html
Copyright © 2011-2022 走看看