【UR #7】水题走四方
题目描述
今天是世界水日,著名的水题资源专家蝈蝈大臣发起了水题走四方活动,向全世界发放成千上万的水题。
蝈蝈大臣是家里蹲大学的教授,当然不愿意出门发水题啦!所以他委托他的助手欧姆来发。
助手欧姆最近做 UR #6 被狗狗传染了懒癌,当然不愿意出门发水题啦!所以他请来了高手 —— 地卜师。
全世界一共 n 个城市,编号分别为 1,…,n。城市之间由双向道路相连,形成了一棵树。如果这棵树以 1 为根,则除 1 以外每个结点 v 的父亲结点的编号 pv 满足 pv<v。
由于地卜师掌握了克隆的核心科技,把自己完全复制了一份,他和他的分身一共两个地卜师一起出去执行任务。
现在,两个地卜师都站在 1 号城市。地卜师可以沿道路行走,从一个城市移动到另一个城市。走一条道路需要耗时 1 小时。当然,地卜师可以停留在某个城市不动。每到一个没有发放水题的城市,地卜师都会发水题。在一个城市里发水题的时间不计。
由于地卜师有强迫症,他沿道路移动时总是从一个城市移动到编号更大的城市。即总是从一个结点移动到它的儿子结点。地卜师和他的分身可以同时移动。
但是地卜师这样好像不一定能经过所有的城市?没关系!地卜师会瞬移。如果某个时刻两个地卜师都在某个城市里(而不是在去某个城市的道路上),那么其中一个地卜师可以瞬移到另一个地卜师所在的城市。瞬移所需的时间不计。
现在地卜师想知道,要想顺利给每个城市都发放水题,最短需要多少个小时。
欧姆当然知道怎么计算啦!但是他想考考你。
题解
神仙题.png。
我们可以先考虑最优解是怎么走出来的。
先是这个人和它的分身,初步的想法是他们俩来到了一个节点,然后分身去遍历这颗子树的一些儿子中的叶子结点。
最后剩一个儿子,然后它俩一块走到下一个儿子里面。
但是这种想法少考虑了一些情况(反例就不说了,也就是说不能只考虑往儿子走)。
我们可以将两个人同时停留的地方称作关键点,显然所有的关键点都在一条链上。
那么分身应该遍历这颗子树减去下一颗关键点所在子树的那颗子树的所有叶子结点。
就是在分身遍历最后一个叶子的时候,这个人可以同时往下一个关键点走,等到两个人都到了自己该到的地方,分身再TP到这个人那里。
然后有一个初步的dp想法,就是设dp[i]表示i是一个关键点,两个人第一次到这个点所用的最小时间。
转移:
nl:当前子树内的叶子节点个数,ds:当前子树内叶子结点的深度和,dm[u][v]:u的子树扣掉v的子树后最深的叶子结点的深度,d:节点深度。
更正:上面的第二个min为max。
后面那个东西是在讨论这个人和分身谁先到目的地。
这个dp是n^2的,好像有各种高科技的优化办法然而并不会。。。
我们发现这个式子前面那一坨好像可优化性不大。
考虑后面那个max可不可以为0,那么相当于是说找到一个祖先u使得d[v]<=dm[u,v]。
如果我们对于每个点都找出这个祖先的话,转移就轻松完成了。
我们考虑是不是所有点都能找到这个祖先,肯定不是的,当一个点的deep满足没有其他点和它deep相等时这个点是没有这种祖先的。
这样的点有什么神奇的规律?它们是连续的一条链,就是这个样子的。
一棵树下面多出来的这条链。
因为我们是在叶子的位置统计答案,那么有结论,最优解肯定不在这种叶子上(想想为什么)。
那么我们的任务就变成找这种神奇祖先了。
首先这种神奇祖先肯定是越低越好。
我们可以维护一个链表表示还没找到祖先的节点,在子树合并的时候互相更新一下(因为两颗子树的maxdeep都可以作为更新答案的条件)。
这是最多只会有一颗子树内有节点没有找到祖先(想想为什么),所以我们维护的复杂度是线性的。
代码
- #include<iostream>
- #include<cstdio>
- #define N 5000009
- #define inf 1e18
- using namespace std;
- typedef long long ll;
- inline ll rd(){
- ll x=;char c=getchar();bool f=;
- while(!isdigit(c)){if(c=='-')f=;c=getchar();}
- while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
- return f?-x:x;
- }
- ll n,deep[N],mx_deep[N],sum_deep[N],cnt[N],dp[N];
- int nxt[N],up[N],son[N],tot,fa[N];
- char s[N<<];
- int main(){
- n=rd();
- scanf("%s", s);int v;
- for(int i=;i<n*;i++){
- if(s[i]=='('){
- tot++;
- fa[tot]=v;
- v=tot;
- }
- else v=fa[v];
- }
- for(int i=;i<=n;++i){
- if(fa[i])son[fa[i]]++;
- deep[i]=deep[fa[i]]+;
- }
- for(int i=n;i>=;--i){
- if(!son[i]){
- mx_deep[i]=sum_deep[i]=deep[i];
- cnt[i]=;
- }
- int now=i;
- while(now&&deep[now]<=mx_deep[fa[i]]){
- up[now]=fa[i];
- now=nxt[now];
- }
- while(nxt[fa[i]]&&deep[nxt[fa[i]]]<=mx_deep[i]){
- up[nxt[fa[i]]]=fa[i];
- nxt[fa[i]]=nxt[nxt[fa[i]]];
- }
- if(now)nxt[fa[i]]=now;
- mx_deep[fa[i]]=max(mx_deep[fa[i]],mx_deep[i]);
- sum_deep[fa[i]]+=sum_deep[i];
- cnt[fa[i]]+=cnt[i];
- }
- ll ans=inf;
- for(int i=;i<=n;++i){
- dp[i]=inf;
- if(up[i])dp[i]=dp[up[i]]+sum_deep[up[i]]-sum_deep[i]-(cnt[up[i]]-cnt[i])*deep[up[i]];
- if(son[fa[i]]==)dp[i]=min(dp[fa[i]]+,dp[i]);
- if(!son[i])ans=min(ans,dp[i]);
- }
- if(n==){puts("");return ;}
- cout<<ans;
- return ;
- }
【UR #7】水题走四方的更多相关文章
- 【UR #7】水题走四方 题解
链接:http://uoj.ac/problem/84 20分算法:萌萌的小爆搜,别搜进环里就行. 50分:我们考虑一下最优决策是什么样的.看似很显然的一点就是我们先让本体在原地不动,让分身去遍历子树 ...
- 【UOJ#82】【UR #7】水题生成器(贪心)
[UOJ#82][UR #7]水题生成器(贪心) 题面 UOJ 题解 把\(n!\)的所有约数搜出来,这个个数不会很多. 然后从大往小能选则选就好了. #include<iostream> ...
- #82. 【UR #7】水题生成器
链接:http://uoj.ac/problem/82 今天是世界水日,著名的水题资源专家蝈蝈大臣向世界宣布了他的一项新发明 —— 水题生成器. 每道题目都有一个正整数的难度值.水题生成器虽然强大但是 ...
- hdu 2041:超级楼梯(水题,递归)
超级楼梯 Time Limit: / MS (Java/Others) Memory Limit: / K (Java/Others) Total Submission(s): Accepted Su ...
- Codeforces Round #367 (Div. 2)---水题 | dp | 01字典树
A.Beru-taxi 水题:有一个人站在(sx,sy)的位置,有n辆出租车,正向这个人匀速赶来,每个出租车的位置是(xi, yi) 速度是 Vi;求人最少需要等的时间: 单间循环即可: #inclu ...
- POJ 3176 Cow Bowling (水题DP)
题意:给定一个金字塔,第 i 行有 i 个数,从最上面走下来,只能相邻的层数,问你最大的和. 析:真是水题,学过DP的都会,就不说了. 代码如下: #include <cstdio> #i ...
- URAL 1136 Parliament 二叉树水题 BST后序遍历建树
二叉树水题,特别是昨天刚做完二叉树用中序后序建树,现在来做这个很快的. 跟昨天那题差不多,BST后序遍历的特型,找到最后那个数就是根,向前找,比它小的那块就是他的左儿子,比它大的那块就是右儿子,然后递 ...
- BZOJ USACO 银组 水题集锦
最近刷银组刷得好欢快,好像都是水题,在这里吧他们都记录一下吧(都是水题大家一定是道道都虐的把= =)几道比较神奇的题到时再列出来单独讲一下吧= =(其实我会说是BZOJ蹦了无聊再来写的么 = =) [ ...
- POJ 3984 - 迷宫问题 - [BFS水题]
题目链接:http://poj.org/problem?id=3984 Description 定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, ...
随机推荐
- 模拟ES6中的Promise实现,让原理一目了然
简介 Promise 对象用于延迟(deferred) 计算和异步(asynchronous )计算.一个Promise对象代表着一个还未完成,但预期将来会完成的操作.Promise 对象是一个返回值 ...
- SQL Server GUID 数据迁移至MongoDB后怎样查看?
关键字:SQL Server NEWID():BSON:MongoDB UUID 1.遇到的问题和困惑 SQL Server中的NEWID数据存储到MongoDB中会是什么样子呢?发现不能简单的通过此 ...
- 详解MongoDB中的多表关联查询($lookup)
一. 聚合框架 聚合框架是MongoDB的高级查询语言,它允许我们通过转换和合并多个文档中的数据来生成新的单个文档中不存在的信息. 聚合管道操作主要包含下面几个部分: 命令 功能描述 $projec ...
- Powershell-获取命令和帮助
Get-Help 获取命令的帮助文档 Update -Help 更新帮助文档 Save-Help 保存文档 Get-Help Get-VM 加上-Full参数获取详细说明 [-name] <st ...
- SQLServer无法删除登录名'***',因为该用户当前正处于登录状态解决方法
问题描述: sqlserver在删除登录名的时候提示删除失败 标题: Microsoft SQL Server Management Studio -------------------------- ...
- SQLServer之修改CHECK约束
使用SSMS数据库管理工具修改CHECK约束 1.打开数据库,选择数据表->右键点击->选择设计(或者展开约束,选择约束,右键点击,选择修改,后面步骤相同). 2.选择要修改的数据列-&g ...
- phoenix API服务发布
概述 Elixir 的 Phoenix 框架对于开发 Web 应用非常方便,不仅有 RoR 的便利,还有 Erlang 的性能和高并发优势. 但是应用的发布涉及到 Erlang 和 Elixir 环境 ...
- hello随笔
初次来到博客园,都试一下 我明白了,随笔就是博客咯.日记自对自己可见.再试试分类吧
- Nginx解读内置非默认模块 ngx_http_stub_status_module
1 Background http://nginx.org/en/docs/http/ngx_http_stub_status_module.html ngx_http_stub_status_mod ...
- linux-python3.8安装
环境: centos7.5 版本:python3.8 1.依赖包安装 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-deve ...