树上最长链 Farthest Nodes in a Tree LightOJ - 1094 && [ZJOI2007]捉迷藏 && 最长链
树上最远点对(树的直径)
做法1:树形dp
最长路一定是经过树上的某一个节点的。
因此:
an1[i],an2[i]分别表示一个点向下的最长链和次长链,次长链不存在就设为0;这两者很容易求
an3[i]表示i为根的子树中的答案;an3[u]=max(max{an3[v]}(v是u的子节点),an1[u]+an2[u])
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
struct Edge
{
LL to,dis,next;
}e[];
LL ne,f1[];
bool vis[];
LL ans[],anss,T,TT,n;
void dfs(LL u)
{
vis[u]=true;
LL k=f1[u],v,ma1=,ma2=;
priority_queue<LL> q;
while(k!=)
{
v=e[k].to;
if(!vis[e[k].to])
{
dfs(v);
q.push(ans[v]+e[k].dis);
}
k=e[k].next;
}
if(!q.empty())
ma1=q.top(),q.pop();
if(!q.empty())
ma2=q.top(),q.pop();
anss=max(anss,ma1+ma2);
ans[u]=ma1;
}
int main()
{
LL i,u,v,w;
scanf("%lld",&TT);
for(T=;T<=TT;T++)
{
memset(vis,,sizeof(vis));
memset(ans,,sizeof(ans));
ne=;
anss=;
memset(f1,,sizeof(f1));
scanf("%lld",&n);
for(i=;i<n;i++)
{
scanf("%lld%lld%lld",&u,&v,&w);
e[++ne].to=v;
e[ne].next=f1[u];
e[ne].dis=w;
f1[u]=ne;
e[++ne].to=u;
e[ne].next=f1[v];
e[ne].dis=w;
f1[v]=ne;
}
dfs();
printf("Case %lld: %lld\n",T,anss);
}
return ;
}
做法2:贪心做法&证明
只需要从任意点a1出发遍历整张图找到离a1最远的点u,再从u出发找到离u最远的点v,u到v的路径就是最长路。
同时可以发现一点:到树上任意一点的最长链,一定是这一点到u、v的链之一。
以上得到了一个性质
设路径(s,t)为当前树上任意一条直径,从树上任意一点u出发,到达任意一点v,设len(u,v)为u到v最短路径的长度,则max(len(u,s),len(u,t))>=len(u,v)对于树上任意一点u,链(u,s)和(u,t)之中,至少有一条是所有以u为端点的链中最长的
根据这个性质,可以证明另一个结论:
现在有两棵树,它们分别有直径(s1,t1)和(s2,t2),设两棵树上分别有一个点,为a,b,在a,b之间连一条边得到一个新的无根树,那么新树一定有至少一条直径,其两个端点都在s1,t1,s2,t2中
证明&其他说明:https://blog.csdn.net/rzo_kqp_orz/article/details/52280811
(证明好像不难,反证+分类讨论)
并且可以发现,这些结论还可以向带边/点权(边/点权非负)的情况推广
比如[ZJOI2007]捉迷藏,有一种非常特殊的做法
是基于以上结论的一个推论(就是把合并树换成合并同一棵已知树上的点集)
有一棵给定的树和树上的两个点集s1,s2,设s1,s2的一条直径分别为(a1,b1),(a2,b2),那么点集(s1∪s2)至少有一条直径,其两个端点都在a1,b1,a2,b2中(点集直径定义自行脑补23333)
证明不太会...大概是先把点集都“补全“成连通块,显然直径不变,然后合并,如果合并后不连通那么显然满足,如果连通且两个点集不相交则按照前面的证法,如果连通且点集相交则除去两个块公共部分然后按两个块各自直径端点位置分类讨论,然后再把”补全“时加进去的点去掉,显然直径仍然不变
具体见题解https://www.luogu.org/blog/user7035/solution-p2056
使用欧拉序lca,可以O(1)求两点距离,可以m*log(n)完成此题
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<int,pii> pip;
struct E
{
int to,nxt;
}e[];
int f1[],ne;
int /*p1[100100],*/p2[],pl2[],fa[],dep[];
int l2x[],lft[];
int n,q;
void dfs(int u)
{
/*p1[++p1[0]]=u;*/p2[++p2[]]=u;pl2[u]=p2[];
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa[u])
{
fa[e[k].to]=u;
dep[e[k].to]=dep[u]+;
dfs(e[k].to);
p2[++p2[]]=u;
}
}
namespace ST
{
int st[][],l2n=;
void pre()
{
int i,j;
for(i=;i<=p2[];i++) st[i][]=p2[i];
for(j=;j<=l2x[p2[]];j++)
{
for(i=;i<=p2[]-lft[j]+;i++)
{
st[i][j]=(dep[st[i][j-]]>dep[st[i+lft[j-]][j-]])
?st[i+lft[j-]][j-]:st[i][j-];
}
}
}
int lca(int a,int b)
{
a=pl2[a];b=pl2[b];
if(a>b) swap(a,b);
int k=l2x[b-a+];
return dep[st[a][k]]>dep[st[b-lft[k]+][k]]
?st[b-lft[k]+][k]:st[a][k];
}
int dis(int a,int b)
{
return dep[a]+dep[b]-*dep[lca(a,b)];
}
}
using ST::dis;
namespace S
{
const int N=;
bool ok[N];
pii n1[N];
#define lc (num<<1)
#define rc (num<<1|1)
void upd(int num)
{
ok[num]=ok[lc]|ok[rc];
if(!ok[lc]) {n1[num]=n1[rc];return;}
if(!ok[rc]) {n1[num]=n1[lc];return;}
int t[]={n1[lc].fi,n1[lc].se,n1[rc].fi,n1[rc].se};
pip ans(-,mp(-,-));
int i,j;
for(i=;i<;i++)
{
for(j=i+;j<;j++)
{
ans=max(ans,mp(dis(t[i],t[j]),mp(t[i],t[j])));
}
}
n1[num]=ans.se;
}
void build(int l,int r,int num)
{
if(l==r) {ok[num]=;n1[num].fi=n1[num].se=l;return;}
int mid=l+((r-l)>>);
build(l,mid,lc);build(mid+,r,rc);
upd(num);
//printf("%d %d %d %d\n",l,r,n1[num].fi,n1[num].se);
}
void change(int L,int l,int r,int num)
{
if(l==r) {ok[num]^=;return;}
int mid=l+((r-l)>>);
if(L<=mid) change(L,l,mid,lc);
else change(L,mid+,r,rc);
upd(num);
}
}
char tmp[];
int main()
{
int i,j,a,b;
lft[]=;
for(i=;i<;i++) lft[i]=lft[i-]<<;
for(i=,j=;i<=;i++)
{
while(lft[j+]<=i) j++;
l2x[i]=j;
}
scanf("%d",&n);
for(i=;i<n;i++)
{
scanf("%d%d",&a,&b);
e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
} dfs();ST::pre();
S::build(,n,);
scanf("%d",&q);
while(q--)
{
scanf("%s",tmp);
if(tmp[]=='G')
{
if(S::ok[])
{
printf("%d\n",dis(S::n1[].fi,S::n1[].se));
}
else
{
puts("-1");
} }
else
{
scanf("%d",&a);
S::change(a,,n,);
}
}
return ;
}
(然而貌似常数太大,比好多点分还慢)
http://210.33.19.103/contest/881/problem/1
最长链
树是任意两点间仅有一条路径的联通图,树上的一条链定义为两个点之间的路径。在本题中定义一条链的长度为链上所有点的权值和。现有一棵带点权树,要对它进行一些操作,请你在第一次操作前和每一次操作后输出这棵树的最长链。
输入格式:
输入文件longest.in第一行有两个整数n、m,表示树中点的个数,以及操作个数。
接下去n-1行,每行有两个整数a、b,表示有一条连接a、b两个点的边。
接下去n行,每行有一个整数x,按次序表示n个点的初始点权。
接下去m行,每行表示一个操作。若第一个字母为M,则接下去会有两个整数a、x,表示将第a个点的点权修改为b。 否则第一个字母为C,接下去会有4个整数a、b、c、d,表示将连接a、b的一条边删掉,再添上一条连接c、d的边。
输出格式:
输出文件longest.out共有m+1行,表示第一次操作前以及每一次操作后的树的最长链。
样例输入:
3 2
1 2
1 3
-1000 1 1
C 1 2 2 3
M 1 1
样例输出:
1
2
3
数据范围:
20%的数据1 ≤ n,m ≤ 1000。
另外20%的数据,保证任意时刻此树是一条链。
另外20%的数据,保证没有第二种操作。
另外20%的数据,保证点权非负。
100%的数据,1 ≤ n,m ≤ 100000,|x| ≤ 10000。保证数据合法。
等待...
树上最长链 Farthest Nodes in a Tree LightOJ - 1094 && [ZJOI2007]捉迷藏 && 最长链的更多相关文章
- light oj 1094 Farthest Nodes in a Tree(树的直径模板)
1094 - Farthest Nodes in a Tree problem=1094" style="color:rgb(79,107,114)"> probl ...
- Farthest Nodes in a Tree ---LightOj1094(树的直径)
题目链接:http://lightoj.com/volume_showproblem.php?problem=1094 Given a tree (a connected graph with no ...
- Farthest Nodes in a Tree (求树的直径)
题目链接,密码:hpu Description Given a tree (a connected graph with no cycles), you have to find the farthe ...
- LightOJ1094 - Farthest Nodes in a Tree(树的直径)
http://lightoj.com/volume_showproblem.php?problem=1094 Given a tree (a connected graph with no cycle ...
- lightoj1094 - Farthest Nodes in a Tree
1094 - Farthest Nodes in a Tree PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limi ...
- lightoj 1094 Farthest Nodes in a Tree 【树的直径 裸题】
1094 - Farthest Nodes in a Tree PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: ...
- E - Farthest Nodes in a Tree
Given a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. Th ...
- LightOJ1257 Farthest Nodes in a Tree (II)(树的点分治)
题目给一棵树,边带有权值,求每一点到其他点路径上的最大权和. 树上任意两点的路径都可以看成是经过某棵子树根的路径,即路径权=两个点到根路径权的和,于是果断树分治. 对于每次分治的子树,计算其所有结点到 ...
- LightOJ 1094 - Farthest Nodes in a Tree
http://lightoj.com/volume_showproblem.php?problem=1094 树的直径是指树的最长简单路. 求法: 两遍BFS :先任选一个起点BFS找到最长路的终点, ...
随机推荐
- socket的bind函数是不是只能绑定本地IP,不能绑定外网IP么?
参考: https://bbs.csdn.net/topics/391024376 别瞎猜测. 所谓bind,就是指绑定本地接受端口. 指定ip,是为了分辨多ip主机. --------------- ...
- MySQL 资源大全
干货!MySQL 资源大全 提交 我的留言 加载中 已留言 shlomi-noach 发起维护的 MySQL 资源列表,内容覆盖:分析工具.备份.性能测试.配置.部署.GUI 等. 伯乐在线已在 Gi ...
- pycharm快捷键和一些常用的设置
http://blog.csdn.net/pipisorry/article/details/39909057 在PyCharm /opt/pycharm-3.4.1/help目录下可以找到Refer ...
- C# 谁改了我的代码 使用 Resharper 快速做适配器
C# 谁改了我的代码 本文告诉大家一个特殊的做法,可以修改一个字符串常量 我们来写一个简单的程序,把一个常量字符串输出 private const string str = "linde ...
- Windows下的Jupyter Notebook 的介绍(写给新手)(图文详解)
不多说,直接上干货! Windows下的Python 3.6.1的下载与安装(适合32bits和64bits)(图文详解) Windows下的Jupyter Notebook 安装与自定义启动(图文详 ...
- 【iOS系列】- iOS吸附效果的实现 之 UICollectionView的使用全解
[iOS系列]- iOS吸附效果的实现 之 UICollectionView的使用全解 UICollectionView可以做很多的布局,在iOS开发中较为重要,所以这里就以实例来讲解UICollec ...
- 扩展HtmlHelper
eg3:扩展HtmlHelper 扩展方法类 1 public static class HtmlExtension 2 { 3 /// ...
- css的白富美
1,CSS(Cascading Style Sheet)是用来装饰HTML的,当浏览器读到这样一个样式的时候,它就会按照这个文档进行格式化(渲染) 2,CSS的组成:选择器和声明,声明又包括属性和属性 ...
- Java类加载机制?
深入研究Java类加载机制 类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比 ...
- bash builtin eval
1 在开始执行eval后面的命令之前eval主要做了哪些事情 1.1 去掉反斜杠的quoting 比如\$ac_optarg,会变成$ac_optarg. 1.2 去掉单引号的quoting 比如: ...