【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, ...
随机推荐
- android引用arr包
转载请标明出处,维权必究:https://www.cnblogs.com/tangZH/p/9939494.html android中引用的包一般分为两种: 1.jar包 2.aar包 arr包其实带 ...
- Linux & Windows 环境下 Redis 安装与基本配置
索引: 目录索引 参看代码 GitHub: redis.txt 一.Linux (DeepinOS) 环境 .安装Redis服务 sudo apt-get install redis-server . ...
- SQL查询获得指定格式内容
Oracle中通过修改SQL语句,达到将查询的内容拼接为指定的字符串格式 eg: select '<ta:datagridItem id="' || lower(column_name ...
- python实例一
https://www.cnblogs.com/evablogs/p/6754839.html 有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? 程序分析: 方法一:该 ...
- SQLServer之删除视图
删除视图注意事项 删除视图时,将从系统目录中删除视图的定义和有关视图的其他信息. 还将删除视图的所有权限. 使用 DROP TABLE 删除的表上的任何视图都必须使用 DROP VIEW 显式删除. ...
- Linux(Deepin 15.9) - MySQL5.7 安装
Linux(Deepin 15.9) - MySQL5.7 安装 sudo apt install mysql-server/panda sudo apt install mysql-client/p ...
- java反射(java.lang.reflect) ---普通单例模式唯一性问题
1. 普通的饱汉式.饿汉式 package org.bighead.test2; public class TestPrivate { private String str = "strPr ...
- 安装ESXi部署OVF详细步骤
整个安装部署过程均在个人环境进行.欧克,我们现在开始. 一.安装ESXi 1.Enter回车 2.Enter回车继续 3.F11,接受继续 4.Enter,回车继续(选择安装ESXi的设备) 5.默认 ...
- 5.机器学习——DBSCAN聚类算法
1.优缺点 优点: (1)聚类速度快且能够有效处理噪声点和发现任意形状的空间聚类: (2)与K-MEANS比较起来,不需要输入要划分的聚类个数: (3)聚类簇的形状没有偏倚: (4)可以在需要时输入过 ...
- Fabric动态增加组织【资料】
Fabric在启动之前需要生成Orderer的创世区块和channel的配置区块.也就是说在Fabric网络启动之前我们就必须定好了有哪些Org,而当Fabric已经跑起来之后,想要增加Org却是很麻 ...