CF796C Bank Hacking
思路
放眼整个题解区没有我这种解法,因此来写一篇题解。
既然要求我们选择一个节点作为根,那么我们就枚举根。
接下来的问题就是如何 \(\mathcal{O}(1)\) 或 \(\mathcal O(\log n)\) 计算贡献。
我们可以把节点分为四类:这个节点,这个节点的父亲,这个节点的儿子,另外的节点。
其中第 \(1/2\) 类非常容易解决。难解决的就是这个节点的儿子和另外的节点。
不妨考虑线段树,把这个节点所有的儿子压到一个区间内,为此,我们需要寻找一种新的编号方式。
原本正常把树拍扁都是根据 \(\mathcal DFS\) 序遍历的,现在我们需要以 \(\mathcal BFS\) 序遍历,而且以点 \(i\) 为根时,它原本的父亲 \(fa_i\) 也会变成它的儿子。
于是如此模拟即可。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int const N=1e6+10;
int n,go[N];
struct node{int w,id;}a[N];
int vis[N],fa[N],minx[N],maxx[N],c[N];
vector<int>b[N];
struct Segment_Tree{
#define ls (x<<1)
#define rs (x<<1|1)
#define mid ((l+r)>>1)
int c[N<<2];
inline void build(int x,int l,int r){
if (l==r){c[x]=a[l].w;return;}
build(ls,l,mid);build(rs,mid+1,r);
c[x]=max(c[ls],c[rs]);
}
inline void update(int x,int l,int r,int p,int v){
if (l==r){c[x]=v;return;}
if (p<=mid) update(ls,l,mid,p,v);
else update(rs,mid+1,r,p,v);
c[x]=max(c[ls],c[rs]);
}
inline int query(int x,int l,int r,int ll,int rr){
if (ll<=l && r<=rr) return c[x];
int res=-2e9;
if (ll<=mid) res=max(res,query(ls,l,mid,ll,rr));
if (mid<rr) res=max(res,query(rs,mid+1,r,ll,rr));
return res;
}
}T;
inline bool cmp(node x,node y){return x.id<y.id;}
inline int solve(int x){
int la=0;
if (fa[x]) la=c[fa[x]],T.update(1,1,n,go[fa[x]],-2e9);
T.update(1,1,n,go[x],-2e9);
int res=c[x];
if (minx[x]<=maxx[x]) res=max(res,T.query(1,1,n,minx[x],maxx[x])+1);
if (minx[x]-1>=1) res=max(res,T.query(1,1,n,1,minx[x]-1)+2);
if (maxx[x]+1<=n) res=max(res,T.query(1,1,n,maxx[x]+1,n)+2);
if (fa[x]) res=max(res,la+1),T.update(1,1,n,go[fa[x]],la);
T.update(1,1,n,go[x],c[x]);
return res;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
for (int i=1;i<=n;++i) cin>>a[i].w,c[i]=a[i].w;
queue<int>q;
for (int i=1;i<n;++i){
int u,v;cin>>u>>v;
b[u].push_back(v);
b[v].push_back(u);
}
q.push(1);vis[1]=1;a[1].id=1;
int cnt=1;
while (!q.empty()){
int x=q.front();q.pop();
minx[x]=cnt+1;vis[x]=1;
for (auto v:b[x]){
if (vis[v]) continue;
fa[v]=x;
a[v].id=++cnt;q.push(v);
}
maxx[x]=cnt;
}
for (int i=1;i<=n;++i) go[i]=a[i].id;
sort(a+1,a+n+1,cmp);
T.build(1,1,n);
int ans=9e18;
for (int i=1;i<=n;++i) ans=min(ans,solve(i));
cout<<ans<<'\n';
return 0;
}
CF796C Bank Hacking的更多相关文章
- CF796C Bank Hacking 思维
Although Inzane successfully found his beloved bone, Zane, his owner, has yet to return. To search f ...
- CF796C Bank Hacking 题解
洛谷链接 题目 Although Inzane successfully found his beloved bone, Zane, his owner, has yet to return. To ...
- CF796C Bank Hacking 细节
思路十分简单,答案只有 3 种可能,但是有一些细节需要额外注意一下. code: #include <bits/stdc++.h> #define N 300002 #define set ...
- C. Bank Hacking 解析(思維)
Codeforce 796 C. Bank Hacking 解析(思維) 今天我們來看看CF796C 題目連結 題目 略,請直接看原題. 前言 @copyright petjelinux 版權所有 觀 ...
- Code Forces 796C Bank Hacking(贪心)
Code Forces 796C Bank Hacking 题目大意 给一棵树,有\(n\)个点,\(n-1\)条边,现在让你决策出一个点作为起点,去掉这个点,然后这个点连接的所有点权值+=1,然后再 ...
- codeforce 796C - Bank Hacking(无根树+思维)
题目 Although Inzane successfully found his beloved bone, Zane, his owner, has yet to return. To searc ...
- CodeForces - 796C Bank Hacking
思路:共有n-1条边连接n个点,即形成一棵树.一开始需要选择一个点hack--将这个点视为根结点,与它相邻的点防御值加1,与它相隔一个在线点的点的防御也加1.当根节点被hack,即这个点被删除,又变成 ...
- Codeforces Round #408 (Div. 2) C. Bank Hacking
http://codeforces.com/contest/796/problem/C Although Inzane successfully found his beloved bone, Zan ...
- Codeforces Round #408 (Div. 2)C. Bank Hacking(STL)
题目链接:http://codeforces.com/problemset/problem/796/C 题目大意:有n家银行,第一次可以攻击任意一家银行(能量低于自身),跟被攻击银行相邻或者间接相邻( ...
- Codeforces Round #408 (Div. 2) C.Bank Hacking(二分)
传送门 题意 给出n个银行,银行之间总共有n-1条边,定义i与j有边相连为neighboring,i到j,j到k有边,则定义i到k的关系为semi- neighboring, 每家银行hack的难度为 ...
随机推荐
- 【Shell案例】【awk和循环、NR、格式打印、全局变量、$0、通配符】12、打印每一行出现的数字个数
写一个 bash脚本以统计一个文本文件 nowcoder.txt中每一行出现的1,2,3,4,5数字个数并且要计算一下整个文档中一共出现了几个1,2,3,4,5数字数字总数. 示例: 假设 nowco ...
- python软件开发目录规范
软件开发目录规范 1.文件及目录的名字可以变换 但是思想是不变的 分类管理 2.目录规范主要规定开发程序的过程中针对不同的文件功能需要做不同的分类 myproject项目文件夹 1,bin文件夹 -- ...
- hook 无限debugger(猿人学第十四题)
猿人学第十四题 检测太多了,debugger fiddler替换无法实现.置空也不行.推荐使用hook Function原生的构造 var func_ = Function.prototype.c ...
- Java中将 int[] 数组 转换为 List(ArrayList)
前言 说起数组转换成 ArrayList,很多同学第一反应就是遍历数组,将元素逐个添加到 ArrayList 中,但是这个看着就lower,一般不会这么答. 所以马上就会想到Arrays工具类的 as ...
- 创建并且配置win10系统虚拟机
一.创建Windows10镜像 1.下载地址:https://www.microsoft.com/zh-cn/software-download/windows10 2.制作镜像 完成之后,会生成一个 ...
- Linux基础 文件和目录
文件和目录 前言 本章讨论文件属性和文件系统内容.除了上一章讨论的普通文件,Linux的文件概念还包括:目录.设备等.在Linux系统中,文件的种类包括:普通文件.目录.符号链接.块设备.字符设备.管 ...
- opencv-python学习之旅
opencv-python 操作 *注:在此笔记中只记录下各种函数的使用,规则 详细讲解见https://opencv.apachecn.org/#/docs/4.0.0/2.1-tutorial_p ...
- [常用工具] cvat安装与使用指北
cvat是一个非常好用的标注工具,但是也是非常难以安装的标注工具,所以本文简单讲一讲如何安装与使用cvat.cvat最好在ubuntu18.04安装,windows平台安装难度很大,然后在其他平台使用 ...
- [OpenCV实战]24 使用OpenCV进行曝光融合
目录 1 什么是曝光融合 2 曝光融合的原理 3 代码与结果 4 参考 本教程中,我们将了解使用OpenCV的Exposure Fusion(曝光融合). 1 什么是曝光融合 曝光融合是一种将使用不同 ...
- ArcObjects SDK开发 025 AO中对象的序列化和反序列化
在ArcObjects SDK,序列化接口是IPersistStream,该接口的定义如下. 其中GetClassID函数可以获取实际类型的唯一ID,Load函数是反序列化函数,Save函数为序列化函 ...