二次扫描与换根
时间:2019-06-12
本文章向大家介绍二次扫描与换根,主要包括二次扫描与换根使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
二次扫描与换根
说实话,我很少为树型\(DP\)写文章,一来这是我最喜欢的一类\(DP\)了,二来是……(不知道要编啥了\(QAQ\)
不过这种方法极其有趣,让我有一种想写的欲望。
废话不多说,开题:
总结一下题意:无根树,流量,最大。
好吧讲真的我第一反应是最大流呵呵呵呵……
但是这个\(N\)极其不友好啊(\(200000\)你是要干啥?)
显然最大流是弄不了了,看一下我们似乎只用上了流量和最大这两个条件无根树还没用上呢。
用树型\(DP\)的方法显然是可以的,但是如果我们暴力跑的话显然会\(TLE\)。
暴力做法:每次以一个节点为根,跑一边树型\(DP\),最后取\(Max\)。
再分析一下我们我们的暴力,发现我们并没有用到每一次\(DP\)的结果,相当于是浪费了时间。
那么我们能不能将前面的计算结果理由上呢?显然是可以的。
接下来就是我们的二次扫描与换根。
如图:我们定义一个\(d[x]\),用于记录当我们选\(Root\)为全树的根时,以\(x\)为根的子树的流量\(Max\)。
(我个人习惯将\(Root\)定义为\(1\),你们自己看着办。)
那么,我们就可以利用到先前跑出的答案了。
即有:\(f[y]=d[y]+min(f[x]-min(d[y],dis(x,y)),dis(x,y));\)
\(deg\)为\(1\)时特判一下即可,上代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
inline int read()
{
int f=1,w=0;char x=0;
while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
return w*f;
}
const int N=200010;
int d[N],deg[N],f[N];
int n,num_edge,head[N];
struct Edge{int next,to,dis;} edge[N*2];//双向边,开两倍一定不能忘了!
inline void add(int from,int to,int dis)
{
edge[++num_edge].next=head[from];
edge[num_edge].dis=dis;
edge[num_edge].to=to;
head[from]=num_edge;
}
inline void Work(int pos,int fa)
{
for(int i=head[pos];i;i=edge[i].next)
if(edge[i].to!=fa)
{
Work(edge[i].to,pos);
if(deg[edge[i].to]==1) d[pos]+=edge[i].dis;
else d[pos]+=min(d[edge[i].to],edge[i].dis);
}
}
inline void Dfs(int pos,int fa)
{
for(int i=head[pos];i;i=edge[i].next)
if(edge[i].to!=fa)
{
if(deg[pos]==1) f[edge[i].to]=d[edge[i].to]+edge[i].dis;
else f[edge[i].to]=d[edge[i].to]+min(f[pos]-min(d[edge[i].to],edge[i].dis),edge[i].dis);
Dfs(edge[i].to,pos);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Text1.in","r",stdin);
#endif
int T=read();
while(T--)
{
memset(f,0,sizeof(f));
memset(d,0,sizeof(d));
memset(deg,0,sizeof(deg));
memset(head,0,sizeof(head));
n=read();num_edge=0;
for(int i=1,u,v,d;i<n;i++)
{
u=read(),v=read(),d=read();
add(u,v,d),add(v,u,d);
deg[u]++,deg[v]++;
}
int ans=0;
Work(1,0);f[1]=d[1];Dfs(1,0);
for(int i=1;i<=n;i++) ans=max(f[i],ans);
printf("%d\n",ans);
}
}
原文地址:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/11009599.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- springmvc之RequestMapping结合@PathVariable使用
- springmvc之CookieValue注解
- springmvc之处理模型数据ModelAndView
- springmvc之异常处理ResponseStatusExceptionResolver
- Java矩阵快速幂实现
- 走近STL -- 你好,List
- 我能看懂的MakeFile(自命名,多文件,多目标)
- Posix信号量与cond条件变量,到底该选谁?
- 信号量--System V信号量 与 Posix信号量
- 文件空间映射mmap()函数(是什么,为什么,怎么用)
- C++下shm共享内存模块
- 基于TypeScript封装Axios笔记(九)
- springmvc之SessionAttributes注解所引发的异常
- 【tensorflow2.0】处理文本数据-imdb数据
- springmvc之异常处理DefaultHandlerExceptionResolver