hdu4871

Shortest-path tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 130712/130712 K (Java/Others)

Total Submission(s): 382    Accepted Submission(s): 115

Problem Description
Given a connected, undirected graph G, a shortest-path tree rooted at vertex v is a spanning tree T of G, such that the path distance from root v to any other vertex u in T is the shortest path distance from v to u in G.

We may construct a shortest-path tree using the following method:

We consider a shortest-path tree rooted at node 1. For every node i in the graph G, we choose a shortest path from root to i. If there are many shortest paths from root to i, we choose the one that the sequence of passing nodes' number is lexicographically
minimum. All edges on the paths that we chose form a shortest-path tree.

Now we want to know how long are the longest simple paths which contain K nodes in the shortest-path tree and how many these paths? Two simple paths are different if the sets of nodes they go through are different.
 
Input
The first line has a number T (T <= 10), indicating the number of test cases.

For each test case, the first line contains three integers n, m, k(1<=n<=30000,1<=m<=60000,2<=k<=n), denote the number of nodes, the number of edges and the nodes of required paths.

Then next m lines, each lines contains three integers a, b, c(1<=a, b<=n, 1<=c<=10000),denote there is an edge between a, b and length is c.
 
Output
For each case, output two numbers, denote the length of required paths and the numbers of required paths.
 
Sample Input
1
6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1
 
Sample Output
3 4

题意:

题意其实就是给你一个图,然后让你转换成一棵树,这棵树满足的是根节点1到其余各点的间隔都是图里的最短间隔,并且为了包管这棵树的独一性,路径也必须是最小的。转化成树的办法其实就是跑一次spfa。spfa的时辰记下所有到这个的前驱的边,然后这些边集反向的边补上就是构成所有最短路的边。然后在这些边上跑一次dfs,跑前将边遵守达到点的序号由小到大排序,重视dfs搜的下一个点的间隔必须是最短的才搜,不然的话搜出来的图就是不合错误的。

至此图的项目组转化完了,剩下的就是求一个图里包含了k个点的路径的最长间隔,以及有几许条,类似的题目还有有几许条路径的乘积=k,有几许条路径的和>k,有几许条路径的乘积是完全立方数。。。做法就是典范的树分治。

具体的做法是找出重心,对重心外的项目组递归求解,归并的时辰列举到重心的所有路径,列举的时辰可以用一个全局的map[s].k和map[s].dis分别记录不包含根节点的顶点个数是s的链的个数和该链的最长距离,时刻更新,然后用一个去列举新的项目组的路径,然后经由过程与mp存的信息对比更新答案;

网络赛的解题报告:

首先构造最短路径树。先求根节点到其他节点的最短路径,然后从根节点开始进行深度优先遍历,先遍历节点编号较小的没遍历过的儿子,这样就能处理处最短路径树。

之后找节点数为K的树链。可以用树分治进行求解,在树分治求解过程中,对于每个中心点,处理出该子树中所有节点到中心点的树链,然后枚举每条树链,比如某条树链节点为a,长度为b,则找之前遍历过的树链中节点数位K-a的长度最长的树链,将这两条树链拼起来可以得到节点数为K的树链,用其更新答案。最好一个一个分支分别处理,可以避免考虑同一个分支来的两条树链。这样枚举并且更新信息,还要存方案数。

程序:

#include"stdio.h"
#include"string.h"
#include"iostream"
#include"map"
#include"string"
#include"queue"
#include"stdlib.h"
#include"math.h"
#define M 30009
#define eps 1e-10
#define inf 1000000000
#define mod 1000000000
using namespace std;
struct node
{
int u,w,v,next;
}edge[M*4];
struct Edge
{
int u,v,w;
}p[M*4];
struct st
{
int dis;
__int64 k;
}mp[M];
int t,k,cnt,maxi,MN,ID;
__int64 ans;
int head[M],use[M],dis[M],id[M],num[M],son[M],limit[M];
int cmp(const void *a,const void *b)
{
if((*(struct node*)a).u==(*(struct node*)b).u)
return (*(struct node*)b).v-(*(struct node*)a).v;
else
return (*(struct node*)b).u-(*(struct node*)a).u;
}
void init()
{
t=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)
{
edge[t].u=u;
edge[t].v=v;
edge[t].w=w;
edge[t].next=head[u];
head[u]=t++;
}
void spfa(int s,int n)
{
queue<int>q;
int i;
for(i=1;i<=n;i++)
dis[i]=inf;
memset(use,0,sizeof(use));
dis[s]=0;
use[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
use[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(dis[v]>dis[u]+edge[i].w)
{
dis[v]=dis[u]+edge[i].w;
p[v].u=u;
p[v].w=edge[i].w;
if(!use[v])
{
use[v]=1;
q.push(v);
}
}
}
}
}
void dfs_size(int u,int f)
{
son[u]=1;
limit[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(f!=v&&!use[v])
{
dfs_size(v,u);
son[u]+=son[v];
limit[u]=max(limit[u],son[v]);
}
}
}
void dfs_root(int root,int u,int f)
{
if(son[root]-son[u]>limit[u])
limit[u]=son[root]-son[u];
if(MN>limit[u])
{
MN=limit[u];
ID=u;
}
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(f!=v&&!use[v])
{
dfs_root(root,v,u);
}
}
}
void get_root(int root,int u,int f)
{
dfs_size(u,f);
MN=inf;
dfs_root(root,u,f);
}
void dfs_dis(int u,int f,int Rank,int w)
{
id[cnt++]=u;
num[u]=Rank;
dis[u]=w;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(f!=v&&!use[v])
{
dfs_dis(v,u,Rank+1,w+edge[i].w);
}
}
}
void cal(int u,int f)
{
cnt=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(f==v||use[v])continue;
int last=cnt;
dfs_dis(v,u,2,edge[i].w);
for(int j=last;j<cnt;j++)
{
if(num[id[j]]==k)//根节点的子链点的个数刚好是k
{
if(maxi<dis[id[j]])//更新最长距离,同时更新数量
{
maxi=dis[id[j]];
ans=1;
}
else if(maxi==dis[id[j]])//相等的话ans++;
{
ans++;
}
}
else if(num[id[j]]<k&&mp[k-num[id[j]]].k)//当当前子链点数小于k,则寻找k-num的子链,
{
if(maxi<dis[id[j]]+mp[k-num[id[j]]].dis)//更新最长距离
{
maxi=dis[id[j]]+mp[k-num[id[j]]].dis;
ans=mp[k-num[id[j]]].k;
}
else if(maxi==dis[id[j]]+mp[k-num[id[j]]].dis)//有相等的话ans加上k-num的链的个数
{
ans+=mp[k-num[id[j]]].k;
}
}
}
for(int j=last;j<cnt;j++)//转化为对立链(即不包含根节点的链)
{
if(mp[num[id[j]]-1].dis<dis[id[j]])
{
mp[num[id[j]]-1].dis=dis[id[j]];
mp[num[id[j]]-1].k=1;
}
else if(mp[num[id[j]]-1].dis==dis[id[j]])
{
mp[num[id[j]]-1].k++;
}
}
}
for(int i=0;i<cnt;i++)//注意此时更新mp不要写成memset的形式,否则会超时
mp[i].k=mp[i].dis=0;
}
void dfs_ans(int u,int f)
{
get_root(u,u,f);
cal(ID,ID);
use[ID]=1;
for(int i=head[ID];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!use[v])
{
dfs_ans(v,v);
}
}
}
void solve()
{
memset(mp,0,sizeof(mp));
memset(use,0,sizeof(use));
ans=maxi=0;
dfs_ans(1,1);
printf("%d %I64d\n",maxi,ans);
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m,i;
scanf("%d%d%d",&n,&m,&k);
for(i=0;i<m*2;i+=2)
{
scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);
p[i^1].u=p[i].v;
p[i^1].v=p[i].u;
p[i^1].w=p[i].w;
}
init();
qsort(p,m*2,sizeof(p[0]),cmp);
for(i=0;i<m*2;i++)
add(p[i].u,p[i].v,p[i].w);
spfa(1,n);
init();
for(i=2;i<=n;i++)
{
add(i,p[i].u,p[i].w);
add(p[i].u,i,p[i].w);
}
solve();
}
}

树链剖分-点的分治(点数为k且距离最长的点对)的更多相关文章

  1. 树链剖分 (求LCA,第K祖先,轻重链剖分、长链剖分)

      2020/4/30   15:55 树链剖分是一种十分实用的树的方法,用来处理LCA等祖先问题,以及对一棵树上的节点进行批量修改.权值和查询等有奇效. So, what is 树链剖分? 可以简单 ...

  2. 树链剖分-点的分治(链的点的个数为k的点对数)

    hdu4760 Cube number on a tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 ...

  3. 树链剖分-点的分治(dis[i]+dis[j]==k的点对数量)

    poj2114 Boatherds Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 1195   Accepted: 387 ...

  4. [2016北京集训试题7]thr-[树形dp+树链剖分+启发式合并]

    Description Solution 神仙操作orz. 首先看数据范围,显然不可能是O(n2)的.(即绝对不是枚举那么简单的),我们考虑dp. 定义f(x,k)为以x为根的子树中与x距离为k的节点 ...

  5. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  6. 树分治&树链剖分相关题目讨论

    预备知识 树分治,树链剖分   poj1741 •一棵有n个节点的树,节点之间的边有长度.方方方想知道,有多少个点对距离不超过m 题解 点分治模板题.详见我早上写的http://www.cnblogs ...

  7. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  8. dsu+树链剖分+树分治

    dsu,对于无修改子树信息查询,并且操作支持undo的问题 暴力dfs,对于每个节点,对所有轻儿子dfs下去,然后再消除轻儿子的影响 dfs重儿子,然后dfs暴力恢复轻儿子们的影响,再把当前节点影响算 ...

  9. [luogu4886] 快递员(点分治,树链剖分,lca)

    dwq推的火题啊. 这题应该不算是点分治,但是用的点分治的思想. 每次找重心,算出每一对询问的答案找到答案最大值,考虑移动答案点,使得最大值减小. 由于这些点一定不能在u的两颗不同的子树里,否则你怎么 ...

随机推荐

  1. 释放Ubuntu/Linux系统cache,增加可用内存空间

    某台式机Ubuntu内存共3G,但free的内存只有200M,无法满足scala的jvm需求. 注意用top命令查看才能看到真正的free内存.下面是查看真正内存使用量的另一种命令. watch -n ...

  2. 25个非常实用的jQuery/CSS3应用组件

    今天分享25款功能十分强大的jQuery/CSS3应用插件,欢迎收藏. 1.jQuery水晶样式下拉导航 这是一款非常不错的jQuery多功能下拉菜单插件,菜单外观呈水晶样式,晶莹剔透,功能丰富,包含 ...

  3. Android Activity 传递数据

    activity中数据的传递方式有2中,一种是使用putExtra()传递,另外一种是传递Bundle对象,使用putExtras()方法. 方法一 发送数据 putExtra()传送的是键值对,第一 ...

  4. Spring 4 官方文档学习(七)核心技术之Spring AOP APIs

    请忽略本篇内容!!! 1.介绍 2.Spring中的pointcut API 2.1.概念 2.2.对pointcut的操作 2.3. AspectJ expression pointcut 2.4. ...

  5. e674. 创建并绘制加速图像

    Images in accelerated memory are much faster to draw on the screen. This example demonstrates how to ...

  6. JavaSE(八)集合之Set

    今天这一篇把之前没有搞懂的TreeSet中的比较搞得非常的清楚,也懂得了它的底层实现.希望博友提意见! 一.Set接口 1.1.Set集合概述 Set集合:它类似于一个罐子,程序可以依次把多个对象 “ ...

  7. localhost 和 127.0.0.1

    转自:http://ordinarysky.cn/?p=431localhost与127.0.0.1的区别是什么?相信有人会说是本地ip,曾有人说,用127.0.0.1比localhost好,可以减少 ...

  8. mysqlbinlog工具的作用是什么呢,如何将binary log转换为文本格式?

    需求描述: 今天在看mysqlbinlog这个工具,就在想这个工具到底是干嘛的呢,在mysql数据库中, binary log中记录了数据库内容的变化或者说修改,这些修改是以二进制的方式存储到 bin ...

  9. opencv移植到ubuntu

    原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/ OpenCV 2.2以后版本需要使用Cmake生成makefile文件,因此需要先安装cmake ...

  10. 第四章 Spring.Net 如何管理您的类___IObjectPostProcessor接口

    官方取名叫 对象后处理器 (object post-processor) , 听起来很高级的样子啊!实际上就是所有实现了这个接口的类,增加了两个方法. Spring.Objects.Factory.C ...