题目大意

给你\(n\)个文件的关系,求出某一个点,这个点到叶节点的长度的总距离最短。(相对长度的定义在题目上有说明)

感想

吐槽一下出题人,为什么出的题目怎么难看懂,我看了整整半个小时,才看懂。

题解

首先数据给我们的是一棵树,一开始我审题不仔细以为是到每个节点的距离最短,就以为是要求树的重心。后来发现不对,而且节点之间的距离不怎么好处理,因为以不同的节点为起点,两节点之间的距离是会变化的。需要用树形dp来解决这个问题,首先预处理出以\(u\)为根节点的子树中有多少个叶节点,因为每一个相对路径的结尾都是没有\(/\)符号的,方便我们计算长度,还要预处理出每一个节点到根节点的长度,因为这个长度是一定的,算出来还是方便计算答案。还有一个是整棵树一共有多少个叶节点,因为在我们计算的节点的上方和下方的计算方法是不一样的。
那么我们树形dp定义状态为\(f[v]\)表示以\(v\)为根节点的最小相对距离之和。
核心的转移方程也是非常好理解的:\(f[v]=f[u]-(len[v]+1)*sz[v]+3*(sum-sz[v])\),解释一下:\(u\)为\(v\)的父亲,为什么是从父亲转移到儿子而不是从儿子转移到父亲?因为越靠近根节点的答案和根节点的答案越接近,每次更改只有一个文件的名字,所以我们先转移到儿子。我们考虑一下,每次我们从父亲节点转移到儿子节点,那么儿子节点以下所有叶子节点都会因为起始节点的改变而减少答案,这个减少的答案是\((len[v]+1)\times sz[v]\),什么意思?因为每次都有一个/号,还有一个\(v\)号字符串的长度,这些答案对于每一个叶子节点都会产生减少。同理在\(v\)节点的另外一侧,也就是\(v\)以上的子树,我们会因为其实节点的降低而增加一段的答案,也就是\(3\times(sum-sz[v])\),\(sum-sz[v]\)表示的是另一半子树中叶节点的个数,\(3\)是因为\(../\)的长度是\(3\),那么转移方程就得到了。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
inline LL gll(){
    LL w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 200005
struct edge{
    int to,nt;
}E[N<<1];
LL H[N],len[N],f[N],sz[N],dis[N];
int cnt,sum,n;
LL ans;
bool isleaf[N];
void addedge(int u,int v){
    E[++cnt]=(edge){v,(int)H[u]}; H[u]=cnt;
}
void dfs1(int u){
    for (int e=H[u];e;e=E[e].nt){
        int v=E[e].to;
        dis[v]=dis[u]+len[v]+1; //+1是因为每一次文件之间都有一个/
        dfs1(v); sz[u]+=sz[v];
    }
    if (isleaf[u]) sz[u]=1,dis[u]--,f[1]+=dis[u];//如果是叶节点那么就之间算就可以了
}
void dfs2(int u){
    for (int e=H[u];e;e=E[e].nt){
        int v=E[e].to;
        if (isleaf[v]) continue;
        f[v]=f[u]-(len[v]+1)*sz[v]+3*(sum-sz[v]);//转移方程
        ans=min(ans,f[v]);
        dfs2(v);
    }
}
int main(){
//  File("DirectoryTraversal");
    n=gi();
    for (int i=1;i<=n;i++){
        char s[20]; scanf("%s",s); len[i]=strlen(s);
        int m=gi();
        if (m==0) sum++,isleaf[i]=1;
        for (int j=1;j<=m;j++){
            LL id=gll();
            addedge(i,id);
        }
    }
    dfs1(1); ans=f[1]; dfs2(1);
    printf("%lld\n",ans);
    return 0;
}

[luogu4268][bzoj5195][USACO18FEB]Directory Traversal的更多相关文章

  1. 【常见Web应用安全问题】---4、Directory traversal

    Web应用程序的安全性问题依其存在的形势划分,种类繁多,这里不准备介绍所有的,只介绍常见的一些.  常见Web应用安全问题安全性问题的列表: 1.跨站脚本攻击(CSS or XSS, Cross Si ...

  2. Web for pentester_writeup之Directory traversal篇

    Web for pentester_writeup之Directory traversal篇 Directory traversal(目录遍历) 目录遍历漏洞,这部分有三个例子,直接查看源代码 Exa ...

  3. luogu4268 Directory Traversal (dfs)

    题意:给一个树状的文件结构,让你求从某个文件夹出发访问到所有文件,访问路径字符串长度之和的最小值,其中,访问父节点用..表示,两级之间用/分割 做两次dfs,第一次算DownN[x]和DownS[x] ...

  4. bzoj 5195: [Usaco2018 Feb]Directory Traversal【树形dp】

    注意到目录是一颗树结构,然后就简单了,预以1为根的处理出dis[u]为以这个点为根,到子树内的目录总长,si为子树内叶子数 第二遍dfs换根即可 #include<iostream> #i ...

  5. Directory traversal

    Find the hidden section of the photo galery. 找到相册的隐藏部分. 直接能够目录遍历: 虽然galerie禁止访问,但是密码就在里面----直接爆破或者爬虫 ...

  6. Spring框架中文件目录遍历漏洞 Directory traversal in Spring framework

    官方给出的描述是Spring框架中报告了一个与静态资源处理相关的目录遍历漏洞.某些URL在使用前未正确加密,使得攻击者能够获取文件系统上的任何文件,这些文件也可用于运行SpringWeb应用程序的进程 ...

  7. USACO比赛题泛刷

    随时可能弃坑. 因为不知道最近要刷啥所以就决定刷下usaco. 优先级排在学习新算法和打比赛之后. 仅有一句话题解.难一点的可能有代码. 优先级是Gold>Silver.Platinum刷不动. ...

  8. 前端学HTTP之web攻击技术

    前面的话 简单的HTTP协议本身并不存在安全性问题,因此协议本身几乎不会成为攻击的对象.应用HTTP协议的服务器和客户端,以及运行在服务器上的Web应用等资源才是攻击目标.本文将详细介绍攻击web站点 ...

  9. web安全性测试用例

    建立整体的威胁模型,测试溢出漏洞.信息泄漏.错误处理.SQL 注入.身份验证和授权错误. 1.   输入验证 客户端验证 服务器端验证(禁用脚本调试,禁用Cookies) 1.输入很大的数(如4,29 ...

随机推荐

  1. Flask源码解读--所有可扩展点

    一.前言 flask中有很多可扩展点(笔者这样称呼),其中包含了信号和请求钩子,这些信号和钩子有什么用呢?其主要作用用于帮助我们进行程序的耦合性,当然还可以让我们自定义一些行为.话不多说,通过阅读源码 ...

  2. WPF中的Bitmap与byte

    原文:WPF中的Bitmap与byte public MainWindow() { InitializeComponent(); byte[] b = GetPictureData(@"F: ...

  3. phpstorm 2018.1.2的安装和破解

    1.什么是phpstorm? PhpStorm是一个轻量级且便捷的PHP IDE,其旨在提高用户效率,可深刻理解用户的编码,提供智能代码补全,快速导航以及即时错误检查.但是phpstorm是商业软件, ...

  4. LInq之Take Skip TakeWhile SkipWhile Reverse Union Concat 用法

    废话不多说,直接上代码,代码有注释!自行运行测试! class Program { static void Main(string[] args) { string[] names = { " ...

  5. mybatis 思考

    https://my.oschina.net/xianggao/blog/548579 https://my.oschina.net/xianggao/blog/548873 https://my.o ...

  6. 从源码的角度再看 React JS 中的 setState

    在这一篇文章中,我们从源码的角度再次理解下 setState 的更新机制,供深入研究学习之用. 在上一篇手记「深入理解 React JS 中的 setState」中,我们简单地理解了 React 中 ...

  7. ZooKeeper 典型的应用场景——及编程实现

    如何使用 Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储,但是 Zookeeper 并不是用来专门存储 ...

  8. OSG 改变窗口大小

    viewer.realize();//需要realize,否则窗口为null osgViewer::GraphicsWindow *pWnd = dynamic_cast<osgViewer:: ...

  9. 第八章Jdk代理 cglib代理

    什么是代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能. 这 ...

  10. shell脚本第一课

    shell脚本的文件名一般是以.sh结尾,也可以以其他格式如.txt,甚至不加后缀. 脚本的第一行的#!/bin/bash表示指定脚本执行时的解析器. #!/bin/bash #文件名:test.sh ...