树链剖分-点的分治(点数为k且距离最长的点对)
Shortest-path tree
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.
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.
1
6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1
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且距离最长的点对)的更多相关文章
- 树链剖分 (求LCA,第K祖先,轻重链剖分、长链剖分)
2020/4/30 15:55 树链剖分是一种十分实用的树的方法,用来处理LCA等祖先问题,以及对一棵树上的节点进行批量修改.权值和查询等有奇效. So, what is 树链剖分? 可以简单 ...
- 树链剖分-点的分治(链的点的个数为k的点对数)
hdu4760 Cube number on a tree Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65535/65535 ...
- 树链剖分-点的分治(dis[i]+dis[j]==k的点对数量)
poj2114 Boatherds Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 1195 Accepted: 387 ...
- [2016北京集训试题7]thr-[树形dp+树链剖分+启发式合并]
Description Solution 神仙操作orz. 首先看数据范围,显然不可能是O(n2)的.(即绝对不是枚举那么简单的),我们考虑dp. 定义f(x,k)为以x为根的子树中与x距离为k的节点 ...
- BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector
题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...
- 树分治&树链剖分相关题目讨论
预备知识 树分治,树链剖分 poj1741 •一棵有n个节点的树,节点之间的边有长度.方方方想知道,有多少个点对距离不超过m 题解 点分治模板题.详见我早上写的http://www.cnblogs ...
- 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分
树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...
- dsu+树链剖分+树分治
dsu,对于无修改子树信息查询,并且操作支持undo的问题 暴力dfs,对于每个节点,对所有轻儿子dfs下去,然后再消除轻儿子的影响 dfs重儿子,然后dfs暴力恢复轻儿子们的影响,再把当前节点影响算 ...
- [luogu4886] 快递员(点分治,树链剖分,lca)
dwq推的火题啊. 这题应该不算是点分治,但是用的点分治的思想. 每次找重心,算出每一对询问的答案找到答案最大值,考虑移动答案点,使得最大值减小. 由于这些点一定不能在u的两颗不同的子树里,否则你怎么 ...
随机推荐
- 關於 WebClient wc = new WebClient() 下載第三方數據不能進安安信任異常
報錯異常:The underlying connection was closed: Could not establish trust relationship for SSL/TLS secure ...
- 采用thinkphp中f方法实现快速缓存实例
一般使用文件方式的缓存就能够满足要求,而thinkphp还提供了一个专门用于文件方式的快速缓存方法f方法. 由于采用的是php返回方式,所以其效率较s方法较高. f方法具有如下特点: 1.简单数据缓存 ...
- 【转】DWM 窗体玻璃效果实现
我一直盼望着 Windows 新版本的发布.令人感兴趣的事情莫过于浏览 MSDN® 和 SDK 文档,查找一些可以利用和依赖的最新创新,然后让朋友和同事以及您的老板(如果幸运的话)大开眼界.Windo ...
- mips cfe命令
设置串口参数 setenv -p LINUX_CMDLINE "console=ttyS0,115200 root=mtd4 rw rootfstype=jffs2" 内核启动参数 ...
- Eclipse 调试总进入Spring代理的解决办法
一直都是跳入代理类中,手动切换查看内容,还以为别人也是这样,结果被告知不是.瞬间囧囧. 搜了一番,看起来有两个办法. 第一个:使用step filter,过滤掉不需要的package.--未测试 第二 ...
- Swing开发图形界面有如下优势
Swing开发图形界面有如下优势 : Swing组件不再依赖于本地平台的GUI,无须采用各种平台的GUI交集,因此Swing提供了大量图形界面组件,远远超出了AWT所提供的图形界面组件集. Swing ...
- (转)platform_driver_register,什么时候调用PROBE函数 注册后如何找到驱动匹配的设备
platform_driver_register,什么时候调用PROBE函数 注册后如何找到驱动匹配的设备 2011-10-24 19:47:07 分类: LINUX kernel_init中d ...
- c++ mktime()
今天联系写一个日历的程序,需要算出月份中的第一天是星期几,用到了mktime()这个函数,感觉这个函数挺有用的,分享给大家. 原型:time_t mktime(struct tm *) 其中的tm结构 ...
- ubuntu server install 安装中文(搜狗)输入法
1.对于ubuntu server默认无中文输入法框架,我比较倾向于我一直使用的ibus-sunpinyin.这里我需要先安装ibus的框架 不过我遇到了问题: dpkg: dependency pr ...
- pushlet 之 Pushlet使用手把手实例
Pushlet(一种comet 架构的实现)是基于Servlet 机制,数据从server端的Java 对象直接推送(push) 到客户端浏览器的(动态)HTML 页面,而无需任何Java app ...