树上最远点对(树的直径)

做法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]捉迷藏 && 最长链的更多相关文章

  1. light oj 1094 Farthest Nodes in a Tree(树的直径模板)

    1094 - Farthest Nodes in a Tree problem=1094" style="color:rgb(79,107,114)"> probl ...

  2. Farthest Nodes in a Tree ---LightOj1094(树的直径)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1094 Given a tree (a connected graph with no ...

  3. Farthest Nodes in a Tree (求树的直径)

    题目链接,密码:hpu Description Given a tree (a connected graph with no cycles), you have to find the farthe ...

  4. LightOJ1094 - Farthest Nodes in a Tree(树的直径)

    http://lightoj.com/volume_showproblem.php?problem=1094 Given a tree (a connected graph with no cycle ...

  5. lightoj1094 - Farthest Nodes in a Tree

    1094 - Farthest Nodes in a Tree   PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limi ...

  6. lightoj 1094 Farthest Nodes in a Tree 【树的直径 裸题】

    1094 - Farthest Nodes in a Tree PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: ...

  7. 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 ...

  8. LightOJ1257 Farthest Nodes in a Tree (II)(树的点分治)

    题目给一棵树,边带有权值,求每一点到其他点路径上的最大权和. 树上任意两点的路径都可以看成是经过某棵子树根的路径,即路径权=两个点到根路径权的和,于是果断树分治. 对于每次分治的子树,计算其所有结点到 ...

  9. LightOJ 1094 - Farthest Nodes in a Tree

    http://lightoj.com/volume_showproblem.php?problem=1094 树的直径是指树的最长简单路. 求法: 两遍BFS :先任选一个起点BFS找到最长路的终点, ...

随机推荐

  1. 如何删除Windows 7的保留分区

    Windows 7的保留分区可以删除,但是必须小心.启动到Windows 7,运行具有管理员权限的CMD.exe,然后输入:diskpartsel disk 0list volsel vol 0 (你 ...

  2. HadoopMapReduce运行机制

    1.map方法读取一个文件的一行记录进行分析,  输入:LongWritable(当前读取的文件位置), Text(内容) 2.map将读取到的信息进行分类,输入Context  (键值对)  ;作为 ...

  3. VC++ VS2010 error LNK1123 转换到 COFF 期间失败 怎么办

    1 无法输出Hello world   2 点击项目-属性,打开属性页   3 配置属性-清单工具-输入和输出-嵌入清单改成否   4 找出计算机中的所有cvtres.exe,删掉早期的,只留最新版的 ...

  4. Java第二次作业參考代码

    Java第二次作业參考代码 [程序11] 题目:有1.2.3.4四个数字,能组成多少个互不同样且无反复数字的三位数?都是多少? public class lianxi11 { public stati ...

  5. robotframework接口自动化

    robot framework框架在测试接口上比soapUI好用的多,在此介绍下get方法的HTTP接口,其实这个接口也是把POST数据作为参数进行get请求,使用post 方法也是一样,一共6步就可 ...

  6. 蓝牙4.0BLE cc2540 usb-dongle的 SmartRF Packet Sniffer 抓取数据方法 【原创,多图】

    蓝牙4.0BLE cc2540 usb-dongle的 SmartRF Packet Sniffer 抓取数据方法 [原创,多图] spm=a1z10.1.w4004-5319414070.11.Zd ...

  7. 使用JDBC 插入向数据库插入对象

    package com.ctl.util; import java.io.IOException; import java.lang.reflect.Field; import java.lang.r ...

  8. Virtual IP address

    https://en.wikipedia.org/wiki/Virtual_IP_address Virtual IP address From Wikipedia, the free encyclo ...

  9. is id() == 从内存的最小化占用角度解释 我是孕育者,我也应该这样设计 变,必然伴随着加法 一个list是否可以执行set()

    def f(a, b): print(a is b, b is a, a == b, a.__eq__(b), id(a), id(b)) f(2, 2) f([2], [2]) f('2', '2' ...

  10. XMU 1607 nc与点对距离 【线段树】

    1607: nc与点对距离 Time Limit: 5000 MS  Memory Limit: 512 MBSubmit: 60  Solved: 8[Submit][Status][Web Boa ...