zoukankan      html  css  js  c++  java
  • [树上差分][lca] Luogu P3258 松鼠的新家

    题目描述

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

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

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

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

    题解

    • 就是一道比较裸的树上差分题目

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #define N 300010
     5 using namespace std;
     6 struct edge{ int to,from,v; }e[N*2];
     7 int n,cnt,head[N],f[40][N],deep[N],a[N],cf[N],vis[N];
     8 void insert(int x,int y)
     9 {
    10     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt;
    11     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt;
    12 }
    13 int lca(int x,int y)
    14 {
    15     if (deep[x]<deep[y]) swap(x,y);
    16     for (int i=30;i>=0;i--) if (deep[f[i][x]]>=deep[y]) x=f[i][x];
    17     if (x==y) return x;
    18     for (int i=30;i>=0;i--) if (f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
    19     return f[0][x];
    20 }
    21 void dfs(int x,int fa)
    22 {
    23     f[0][x]=fa,deep[x]=deep[fa]+1;
    24     for (int i=head[x];i;i=e[i].from) if (e[i].to!=fa) dfs(e[i].to,x);
    25 }
    26 int dfs1(int x)
    27 {
    28     int ans=cf[x]; vis[x]=1;
    29     for (int i=head[x];i;i=e[i].from) if (!vis[e[i].to]) ans+=(e[i].v=dfs1(e[i].to));
    30     for (int i=head[x];i;i=e[i].from) if (e[i].to==f[0][x]) e[i].v=ans,i=0;
    31     return ans;
    32 }
    33 int main()
    34 {
    35     scanf("%d",&n);
    36     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    37     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y);
    38     dfs(a[1],a[1]);
    39     for (int i=1;(1<<i)<=n;i++) for (int j=1;j<=n;j++) f[i][j]=f[i-1][f[i-1][j]];
    40     for (int i=1;i<n;i++)  cf[a[i]]++,cf[a[i+1]]++,cf[lca(a[i],a[i+1])]-=2;
    41     memset(vis,0,sizeof(vis)),dfs1(a[1]);
    42     for (int i=1;i<=n;i++)
    43     {
    44         int ans=0;
    45         for (int j=head[i];j;j=e[j].from) ans+=e[j].v;
    46         if (i==a[n]) ans--; printf("%d
    ",(ans+1)/2);
    47     }
    48 }
  • 相关阅读:
    浅谈ASP.NET核心对象
    SQL MID() 函数
    如何查看linux系统CPU利用率 简单
    canvas 学习笔记 简单
    linux 为用户设定、修改密码 passwd 简单
    转crontab用法(例子) 简单
    mongodb加入系统服务 简单
    转导出csv文件时,处理分隔符问题 简单
    tar和gzip、unzip命令详解 简单
    linux创建用户命令 简单
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11333974.html
Copyright © 2011-2022 走看看