• P3258 [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

    //记录从哪一个房间出发,update(出发点,终点,add)
    //因为从房间出发的时候不需要糖果,到达的时候才需要糖果
    //所以update的时候会在出发点多放一块糖果
    //那我们就update(s,s,-1),把多放的那块减去
    //第一个房间是起点,提前在for循环外边放上一块糖。 
    //last记录起点是谁
    //这样,在每次update之前都先把last上的糖--,然后update(区间)
    //最后让终点的糖--,因为题目中说最后一个点是餐厅,不用放糖 
    
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    const int N=3e5+5;
    
    int n;
    int a[N];
    int head[N],num_edge;
    struct Edge
    {
        int v,nxt;
    }edge[N<<1];
    struct NODE
    {
        int fa,son;
        int top,dep;
        int s,t;
        int size;
    }node[N];
    struct TREE
    {
        TREE *lson,*rson;
        int l,r,mid,len;
        int sum,add;
    }tree[N<<2];
    
    typedef TREE* Tree;
    Tree now_node=tree,Root;
    
    inline int read()
    {
        char c=getchar();int num=0;
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num;
    }
    
    inline void add_edge(int u,int v)
    {
        edge[++num_edge].v=v;
        edge[num_edge].nxt=head[u];
        head[u]=num_edge;
    }
    
    void dfs1(int u)
    {
        node[u].size=1;
        for(int i=head[u],v;i;i=edge[i].nxt)
        {
            v=edge[i].v;
            if(v==node[u].fa)
                continue;
            node[v].fa=u;
            node[v].dep=node[u].dep+1;
            dfs1(v);
            node[u].size+=node[v].size;
            if(node[v].size>node[node[u].son].size)
                node[u].son=v;
        }
    }
    
    int bound;
    void dfs2(int u,int top)
    {
        node[u].top=top;
        node[u].s=++bound;
        if(node[u].son)
        {
            dfs2(node[u].son,top);
            for(int i=head[u],v;i;i=edge[i].nxt)
            {
                v=edge[i].v;
                if(v==node[u].son||v==node[u].fa)
                    continue;
                dfs2(v,v);
            }
        }
        node[u].t=bound;
    }
    
    void build(Tree &root,int l,int r)
    {
        root=++now_node;
        root->l=l,root->r=r,root->mid=l+r>>1;
        root->len=r-l+1;
        if(l==r)
            return;
        build(root->lson,l,root->mid);
        build(root->rson,root->mid+1,r);
    }
    
    inline void pushdown(Tree root)
    {
        if(root->add)
        {
            root->lson->add+=root->add;
            root->rson->add+=root->add;
            root->lson->sum+=root->add*root->lson->len;
            root->rson->sum+=root->add*root->rson->len;
            root->add=0;
        }
    }
    
    void update(const Tree &root,int l,int r,int add)
    {
        if(root->l==l&&root->r==r)
        {
            root->sum+=root->len*add;
            root->add+=add;
            return;
        }
        pushdown(root);
        if(r<=root->mid)
            update(root->lson,l,r,add);
        else if(l>root->mid)
            update(root->rson,l,r,add);
        else
        {
            update(root->lson,l,root->mid,add);
            update(root->rson,root->mid+1,r,add);
        }
    //    root->sum=root->lson->sum+=root->rson->sum;        不用pushup 
    }
    
    int query(const Tree &root,int pos)
    {
        if(root->l==root->r)
            return root->sum;
        pushdown(root);
        if(pos<=root->mid)
            return query(root->lson,pos);
        else
            return query(root->rson,pos);
    }
    
    inline void Modify(int x,int y)
    {
        int fx=node[x].top,fy=node[y].top;
        while(fx!=fy)
        {
            if(node[fx].dep>node[fy].dep)
            {
                update(Root,node[fx].s,node[x].s,1);
                x=node[fx].fa;
                fx=node[x].top;
            }
            else
            {
                update(Root,node[fy].s,node[y].s,1);
                y=node[fy].fa;
                fy=node[y].top;
            }
        }
        if(node[x].dep>node[y].dep)
            update(Root,node[y].s,node[x].s,1);
        else
            update(Root,node[x].s,node[y].s,1);
    }
    
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;++i)
            a[i]=read();
        for(int i=1,u,v;i<n;++i)
        {
            u=read(),v=read();
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs1(1);
        dfs2(1,1);
        build(Root,1,n);
        int last=a[1];
        update(Root,node[last].s,node[last].s,1);    //起点放糖 
        for(int i=2;i<=n;++i)
        {
            update(Root,node[last].s,node[last].s,-1);    //让起点的糖-- 
            Modify(last,a[i]);
            last=a[i];
        }
        update(Root,node[last].s,node[last].s,-1);        //终点的糖-- 
        for(int i=1;i<=n;++i)    //查询每个房间要放多少糖 
            printf("%d
    ",query(Root,node[i].s));
        return 0;
    }
  • 相关阅读:
    Unix进程和线程管理及其异同
    UnixIPC之共享内存
    Unix/Linux常用文件操作
    java中int和Integer比较
    JAVA四种引用类型
    JAVA-Exception&Error
    JAVA特性-跨平台/面向对象
    JAVA单向链表实现
    linux安装及配置c++的opencv库
    static_cast、const_cast、dynamic_cast、reinterpret_cast
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8575846.html
Copyright © 2020-2023  润新知