LOJ 6192 城市网络(树上倍增)
LOJ #6192. 「美团 CodeM 复赛」城市网络(链接)
一棵以 $ 1 $ 号节点为根的树,每个点有一个权值,有 $ q $ 个询问,每次从 $ x $ 点开始往某个祖先 $ y $ 走,初始有权值 $ c $ ,如果路径上遇到更大的权值,那么 $ c $ 改为那个权值,问会修改多少次。数据范围: $ n\leq 2\times 10^5 $
$ solution: $
首先因为本题没有修改操作,所以可以离线维护。然后我们发现如果我们在 $ x $ 处节点被修改权值,那么问题从这个节点开始就等效于:从 $ x $ 节点以其本身权值为初始权值向根节点走。然后此题还有另一个突破口:每一个节点,若以当前节点权值为初始权值,它向根节点走第一个会被修改的节点是确定的!这是倍增的标志!!!
结合上面两个性质,我们可以想出一种做法:用倍增数组 $ f[200005][19] $ 维护祖辈里比他大的节点(第一个比他大的,第二个,第四个,八个........)。如果我们初始权值为 $ v $ ,那么我们只要找到第一个比他大的节点(这个也可以用倍增完成),然后我们在这个节点开始用倍增,因为数组里记录都是比当前节点大的节点,所以我们只需将数组里所有深度小于终点的节点数记录下来即可!
至于预处理,首先我们虚拟一个根节点的父亲,权值无限大。然后更新某个节点处置时,找到父辈里第一个比他大的节点,用这个节点更新当前节点即可。具体寻找时:我们要从父亲节点出发,因为数组里记录的是比他大的节点,我们只需要看看那个节点的权值是否大于当前节点,小于等于才跳,最后得到的节点的父亲即为所求!
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define rg register int
using namespace std;
int n,q;
int top;
int a[400005]; //节点权值
int dp[400005]; //节点深度
int f[300005][19]; //树上倍增
// f数组存的是祖辈里比他大的节点(第一个比他大的,第二个,第四个,八个........)
struct su{
int to,next;
}b[800005];
int tou[400005]; //链式前向星
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
inline int get(int x,int v){ //找到去根节点的路径上第一个比他大的
if(a[x]>v)return x; //x是他父亲
for(rg i=18;i>=0;--i){
if(a[f[x][i]]<=v)x=f[x][i]; //只有都小于等于他才向上跳,倍增套路
}x=f[x][0]; return x; //小于等于才跳,那么下一个就是第一个比他大的
}
inline void dfs(int i,int fa){
dp[i]=dp[fa]+1; //深度
rg x=get(fa,a[i]); f[i][0]=x; //当前节点还没有值,从父亲开始找
for(rg j=0;j<18;++j)
f[i][j+1]=f[f[i][j]][j]; //用第一个比他大的节点更新倍增信息
for(rg j=tou[i];j;j=b[j].next)
if(b[j].to!=fa)dfs(b[j].to,i);
}
inline int ask(int x,int y,int v){
for(rg i=18;i>=0;--i)
if(a[f[x][i]]<=v)x=f[x][i]; //和get函数差不多,找到第一个比他大的
if(a[x]<=v)x=f[x][0]; //有可能初始节点就比v大
if(dp[x]<dp[y])return 0; //说明没有比他大的
rg res=1;
for(rg i=18;i>=0;--i){
if(dp[f[x][i]]>=dp[y])res+=1<<i,x=f[x][i]; //按照深度一点一点逼近
}return res;
}
int main(){
n=qr(); q=qr();
for(rg i=1;i<=n;++i) a[i]=qr();
for(rg i=1;i<n;++i){
rg x=qr(),y=qr();
b[++top].to=y; b[top].next=tou[x]; tou[x]=top; //居然不开c++11
b[++top].to=x; b[top].next=tou[y]; tou[y]=top; // o(一︿一+)o
} a[0]=1e9; dfs(1,0); //根节点的父亲要赋最大!!!
for(rg i=1;i<=q;++i){
rg x=qr(),y=qr(),z=qr();
printf("%d\n",ask(x,y,z));
}
return 0;
}
LOJ 6192 城市网络(树上倍增)的更多相关文章
- LOJ #6192. 「美团 CodeM 复赛」城市网络 (树上倍增)
#6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB 时间限制:500 ms 标准输入输出 题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接 ...
- LibreOJ #6192. 「美团 CodeM 复赛」城市网络
#6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: sqc 提交提交记录统计讨论测试数据 题目描 ...
- (2016北京集训十三)【xsy1532】网络战争 - 最小割树+树上倍增+KD树
题解: 好题!! 这题似乎能上我代码长度记录的前五? 调试时间长度应该也能上前五QAQ 首先题目要求的明显就是最小割,当然在整个森林上求Q次最小割肯定是会GG的,所以我们需要一个能快速求最小割的算法— ...
- 美团 CodeM 复赛」城市网络
美团 CodeM 复赛」城市网络 内存限制:64 MiB时间限制:500 ms标准输入输出 题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接的连通图),首都为 11 ...
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...
- 【bzoj4568】[Scoi2016]幸运数字 树上倍增+高斯消元动态维护线性基
题目描述 A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游 ...
- luogu1081 开车旅行 树上倍增
题目大意 小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i 的海拔高度为Hi,城市i 和城市j 之间的距离 ...
- 『保卫王国 树上倍增dp』
保卫王国 Description Z 国有n座城市,n - 1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需 ...
- 最近公共祖先算法LCA笔记(树上倍增法)
Update: 2019.7.15更新 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了. 万分感谢[宁信]大佬,认认真真地审核了本文章,指出了超过五处错误捂脸,太尴尬了 ...
随机推荐
- 旋转数组 空间复杂度为O(1) 的2 种方法 + 1种空间复杂度O(n)
题目地址 : 旋转数组. 网上好多不是根本就是错的,就是空间复杂度不是真正为1 下面总结一下 方法1 普通方法(空间复杂度不满足要求,但是题目并不会判错,说明他们没用对空间进行校验) ··· publ ...
- 2、node-webkit运行web应用,node-webkit把web应用打包成桌面应用
下面我通过一个简单的demo来介绍怎么样把一个web应用打包成一个可执行文件(这里只介绍windows环境) 首先新建一个index.html文件,作为我们这个demo的入口页面,我们暂且就把这个页面 ...
- JS实现数组排序:升序和降序
如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序.即 a 和 b 是两个将要被比较的元素: 如果 compareFunction(a, b) 小于 0 ,那么 a 会 ...
- lgb参数及调参
1 参数含义 max_depth: 设置树的最大深度,默认为-1,即不限制最大深度,它用于限制过拟合 num_leave: 单颗树的叶子数目,默认为31 eval_metric: 评价指标,可以用lg ...
- Unity Ray 射线
射线:射线是3D世界一个向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,它将停止发射. 用途:射线范围比较广,多用于碰撞检测(如:子弹飞行是否击中目标).角色移动等. Ray是一个结 ...
- 基于Python对象引用、可变性和垃圾回收详解
基于Python对象引用.可变性和垃圾回收详解 下面小编就为大家带来一篇基于Python对象引用.可变性和垃圾回收详解.小编觉得挺不错的,现在就分享给大家,也给大家做个参考. 变量不是盒子 在示例所示 ...
- C# 导出Excel文件 所导出文件打开时提示“Excel文件格式与扩展名指定格式不一致”
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application(); ...
- linux/linux学习笔记-vim文本编辑器(mooc)
vim文本编辑器 vim与vi的区别:( vim=vi +IMproved) VIM是一个Unix以及类unix文本编辑器 特点:功能强大,高度可定制 vim编辑器的三种模式:一般模式.编辑模式和命令 ...
- Go语言入门篇-基本类型排序和 slice 排序
参见博客:https://blog.csdn.net/u010983881/article/details/52460998 package main import ( "sort" ...
- js for 循环
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...