• bzoj3631:[JLOI2014]松鼠的新家


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3631

    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

    题解

    题目要求的是给定一个路径,经过每个点的次数。然后树链剖分,先是两个dfs,第一个dfs求出:子树大*(siz[]),父亲(fa[]),重儿子(son[]),深度(dep[])。第二个dfs求出:所在链的顶端节点(top[]),dfs序中的编号(w[])。一开始看到区间修改会产生用线段树的冲动,但是因为只有到了最后才会需要查询一下,所以可以查分。然后因为除了第一个节点外,从其他每一个节点出发不需要糖果,因为每个点总是在进来的时候已经给了糖果了,所以都要减去一个1,因为终点不用给糖果,所以终点也减去个1

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #define N 300010
    using namespace std;
    int n,p,q,sum,tot;
    int siz[N],fa[N],son[N],top[N],dep[N],w[N];
    int head[N],to[2*N],data[2*N],next[2*N];
    int a[N],ans[N];
    int getint()
    {
        int res=0,w=1;
        char ch=getchar();
        while ((ch>'9' || ch<'0')&&ch!='-') ch=getchar();
        if (ch=='-') w=-1,ch=getchar();
        while (ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar();
        return res*w;
    }
    void link(int x,int y) {next[++sum]=head[x]; head[x]=sum; to[sum]=y;}
    void dfs1(int p,int Fa)
    {
        siz[p]=1;
        for (int i=head[p];i;i=next[i])
            {
                if (to[i]!=Fa)
                    {
                        fa[to[i]]=p; dep[to[i]]=dep[p]+1;
                        dfs1(to[i],p);
                        siz[p]+=siz[to[i]];
                        if (siz[to[i]]>siz[son[p]]) son[p]=to[i];
                    }
            }
    }
    void dfs2(int p,int t)
    {
        top[p]=t; w[p]=++tot;
        if (son[p]) dfs2(son[p],t);
        for (int i=head[p];i;i=next[i])
            if (to[i]!=fa[p]&&to[i]!=son[p]) dfs2(to[i],to[i]);
    }
    void jia(int x,int y) {ans[x]++; ans[y+1]--;}
    void find(int p,int q)
    {
        while (top[p]!=top[q])
            {
                if (dep[top[p]]<dep[top[q]]) swap(p,q);
                jia(w[top[p]],w[p]);
                p=fa[top[p]];
            }
        if (dep[p]>dep[q]) swap(p,q);
        jia(w[p],w[q]);
    }
    int main()
    {
    
        n=getint();
        for (int i=1;i<=n;i++) a[i]=getint();
        for (int i=1;i<=n-1;i++)
            {
                p=getint(); q=getint(); link(p,q); link(q,p);
            }
        dfs1(1,0); dfs2(1,1);
        for (int i=1;i<n;i++) find(a[i],a[i+1]);
        for (int i=1;i<=n;i++) ans[i]+=ans[i-1];
        for (int i=1;i<=n;i++)
            {
                if (i==a[1]) printf("%d
    ",ans[w[i]]);
                else printf("%d
    ",ans[w[i]]-1);
            }
        return 0;
    }
    转载请联系博主!!!
  • 相关阅读:
    第一节:理解垃圾回收平台的基本工作原理
    回想笔记 瞎比比 域名注册 解析绑定ip 下载证书 设置证书 重定向http到https请求
    flask 设置https请求 访问flask服务器
    关于 服务器ip和域名进行一个绑定
    ubuntu 安装flask+nginx+gunicorn 待定
    使用flask-dropzone 上传图片文件
    flask 对于用户登录保持状态 flask_login
    flask 对于邮件url进行一个加密防止爆破
    flask 密码加密 视频资料
    flask 多线程邮件异步发送 视频资料
  • 原文地址:https://www.cnblogs.com/xiaoqiang200015/p/5981037.html
Copyright © 2020-2023  润新知