zoukankan      html  css  js  c++  java
  • [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


    题解

      

         可以说是一道树链剖分的模板题吧

         但是注意一下有坑

         

         参观的n 个房间并不一定包括了所有的房间!

         e.g. 参观1->2->1->3->1 

         以及最坏情况需要开long long


    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define ll long long 
    using namespace std;
    const int N=300010;
    struct node{
        int to,next;
    }e[N<<1];
    int dep[N],fa[N],sum[4*N],lazy[4*N],num,head[N],dic[N];
    int size[N],son[N],ch[N],now,n,l[N],top[N],tot;
    void add(int from,int to)
    {
        num++;
        e[num].to=to;
        e[num].next=head[from];
        head[from]=num;
    }
    
    void push(int root,int l,int r)
    {
        int mid=(l+r)>>1;
        lazy[root<<1]+=lazy[root];
        lazy[root<<1|1]+=lazy[root];
        sum[root<<1]+=lazy[root]*(mid-l+1);
        sum[root<<1|1]+=lazy[root]*(r-mid);
        lazy[root]=0;
        return ;
    }
    
    void update(int root,int left,int right,int l,int r,int k)
    {
        if(l>right||r<left)return ;
        if(l<=left&&right<=r)
        {
            sum[root]+=k*(right-left+1);
            lazy[root]+=k;
            return ;
        }
        int mid=(left+right)>>1;
        if(lazy[root])push(root,left,right);
        if(mid>=l)update(root<<1,left,mid,l,r,k);
        if(r>mid) update(root<<1|1,mid+1,right,l,r,k);
        sum[root]=sum[root<<1]+sum[root<<1|1];
        return ;
    }
    
    ll query(int root,int left,int right,int l,int r)
    {
        if(l>right||r<left)return 0;
        if(l<=left&&right<=r)return sum[root];
        int mid=(left+right)>>1;
        if(lazy[root])push(root,left,right);
        ll a=0,b=0;
        if(mid>=l)a=query(root<<1,left,mid,l,r);
        if(mid<r) b=query(root<<1|1,mid+1,right,l,r);
        return a+b;
    }
    
    void dfs1(int x)
    {
        size[x]=1;
        for(int i=head[x];i;i=e[i].next)
        {
            int v=e[i].to;
            if(!dep[v])
            {
                dep[v]=dep[x]+1;
                fa[v]=x;
                dfs1(v);
                size[x]+=size[v];
                if(size[v]>size[son[x]])son[x]=v;
            }
        }
        return ;
    }
    
    void dfs2(int x,int t)
    {
        l[x]=++tot;top[x]=t;
        if(son[x])dfs2(son[x],t);
        for(int i=head[x];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v!=fa[x]&&v!=son[x])
            {
                dfs2(v,v);
            }
        }
        return ;
    }
    
    void cap(int x,int y)
    {
        int fx=top[x],fy=top[y];
        while(fx!=fy)
        {
            if(dep[fx]<dep[fy])
            {
                swap(fx,fy);swap(x,y);
            }
            update(1,1,n,l[fx],l[x],1);
            x=fa[fx];
            fx=top[x];
        }
        if(l[x]>l[y])
        swap(x,y);
        update(1,1,n,l[x],l[y],1);
        return ;
    }
    
    ll read()
    {
        ll x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
        {
            ch[i]=read();
            if(i!=1)dic[ch[i]]++;
        }
        for(int i=1;i<n;i++)
        {
            int x,y;
            x=read();y=read();
            add(x,y);add(y,x);
        }
        dep[1]=1;
        fa[1]=0;
        dfs1(1);
        dfs2(1,1);
        
        for(int i=2;i<=n;i++)
        {
            cap(ch[i-1],ch[i]);
        }
        for(int i=1;i<=n;i++)
        {
            cout<<query(1,1,n,l[i],l[i])-dic[i]<<endl;
        }
        return 0;
    }
  • 相关阅读:
    使用linux将一个服务器上的文件或者文件夹复制黏贴到另一个服务器上
    深度学习之常用linux命令总结
    python 操作MYSQL数据库
    MYSQL登录及常用命令
    mysql数据库可视化工具—Navicat Premium—安装与激活
    Mysql数据库的简单介绍与入门
    java 正则匹配int型
    js设置文本框只能输入数字
    Java数据抓取(一)
    Nodejs的多线程
  • 原文地址:https://www.cnblogs.com/hhh1109/p/8780494.html
Copyright © 2011-2022 走看看