• luogu 3258 [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

    分析

    一道树上差分 + LCA的题

    需要注意的是,每一次只对路径上的点candy+1,所以LCA要-1,而father[LCA]也要-1

    最后输出时要-1是因为到达这个点时拿了一次糖,每次离开这个点的时候就不拿糖了

    末尾的哪一个房间因为没有离开,本身不应该-1,现在输出时-1正好解决了题中“最后一个房间不拿糖”。

    而第一个房间因为一开始就在,所以没有在“到达的时候”拿糖,输出时也不应该-1,所以输出前要++(注意是在最后一次DFS后++)

    代码

      1 /*********************
      2 User:Mandy.H.Y
      3 Language:c++
      4 Problem:luogu3258
      5 Algorithm: 
      6 *********************/
      7 
      8 #include<bits/stdc++.h>
      9 
     10 using namespace std;
     11 
     12 const int maxn = 3e5 + 5;
     13 
     14 int n,size;
     15 int a[maxn],first[maxn];
     16 int dep[maxn],father[maxn],top[maxn],cnt[maxn];
     17 int candy[maxn];
     18 
     19 struct Edge{
     20     int v,nt;
     21 }edge[maxn << 1];
     22 
     23 
     24 template<class T>inline void read(T &x){
     25     x = 0;bool flag = 0;char ch = getchar();
     26     while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
     27     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
     28     if(flag) x = -x;
     29 }
     30 
     31 template<class T>void putch(const T x){
     32     if(x > 9) putch(x / 10);
     33     putchar(x % 10 | 48);
     34 }
     35 
     36 template<class T>void put(const T x){
     37     if(x < 0) putchar('-'),putch(-x);
     38     else putch(x);
     39 }
     40 
     41 void file(){
     42     freopen("3258.in","r",stdin);
     43     freopen("3258.out","w",stdout);
     44 }
     45 
     46 void eadd(int u,int v){
     47     edge[++size].v = v;
     48     edge[size].nt = first[u];
     49     first[u] = size;
     50 }
     51 
     52 void readdata(){
     53     read(n);
     54     for(int i = 1;i <= n; ++ i){
     55         read(a[i]);
     56     }
     57     for(int i = 1;i < n; ++ i){
     58         int u,v;
     59         read(u);read(v);
     60         eadd(u,v);
     61         eadd(v,u);
     62     }
     63 }
     64 
     65 void dfs(int u,int f,int d){
     66     top[u] = u;father[u] = f;
     67     dep[u] = d;cnt[u] = 1;
     68     int son = 0,mcnt = 0;
     69     
     70     for(int i = first[u];i;i = edge[i].nt){
     71         int v = edge[i].v;
     72         if(v == f) continue;
     73         dfs(v,u,d + 1);
     74         cnt[u] += cnt[v];
     75         if(cnt[v] > mcnt){
     76             mcnt = cnt[v];
     77             son = v;
     78         }
     79     }
     80     if(son) top[son] = u;
     81 }
     82 
     83 int find(int x){
     84     return top[x] == x ? x : top[x] = find(top[x]);
     85 }
     86 
     87 int LCA(int x,int y){
     88     if(find(x) == find(y)) return dep[x] < dep[y] ? x : y;
     89     else return dep[top[x]] < dep[top[y]] ? LCA(x,father[top[y]]) : LCA(father[top[x]],y);
     90     //又打错了 
     91 }
     92 
     93 void dfs1(int u,int f){
     94     for(int i = first[u];i;i = edge[i].nt){
     95         int v = edge[i].v;
     96         if(v == f) continue;
     97         dfs1(v,u);
     98         candy[u] += candy[v];
     99     }
    100 }//统计糖果 
    101 
    102 void work(){
    103     dfs(1,0,1);
    104     for(int i = 2;i <= n ; ++ i){
    105         int anc = LCA(a[i],a[i-1]);
    106         candy[a[i]]++;
    107         candy[a[i-1]]++;
    108         candy[anc]--;
    109         candy[father[anc]]--;
    110         //只对路径上的点有贡献,对LCA以上的点无贡献 
    111     }
    112     dfs1(1,0);
    113     candy[a[1]]++;
    114 //末尾的哪一个房间因为没有离开,本身不应该-1,现在输出时-1正好解决了题中“最后一个房间不拿糖”。
    115 //而第一个房间因为一开始就在,所以没有在“到达的时候”拿糖,输出时也不应该-1,所以输出前要++(注意是在最后一次DFS后++)
    116     for(int i = 1;i <= n; ++ i){
    117         put(candy[i]-1);putchar('
    ');
    118         //    最后输出时要-1是因为到达这个点时拿了一次糖,每次离开这个点的时候就不拿糖了
    119         //但是算路径上的糖时要用,所以在输出时-1; 
    120     }
    121 }
    122 
    123 int main(){
    124 //    file();
    125     readdata();
    126     work();
    127     return 0;
    128 }
    View Code
    非做顽石不可,哪管他敬仰暗唾
  • 相关阅读:
    Linux_Bash脚本基础
    Linux_Bash脚本基础
    Windows perl dbi oracle环境配置
    第八章 引用:
    bless 概念
    电力企业信息化建设解决方案之计量生产分析系统
    Tom和Jerry来了,Tom和Jerry走了——北漂18年(38)
    电力企业信息化建设解决方案之计量生产分析系统
    请用fontAwesome代替网页icon小图标
    Python Module_openpyxl_处理Excel表格
  • 原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11414289.html
Copyright © 2020-2023  润新知