您的位置:首页 > 其它

bzoj 4016: [FJOI2014]最短路径树问题

2016-12-21 21:36 387 查看

4016: [FJOI2014]最短路径树问题

Time Limit: 5 Sec  Memory Limit: 512 MB
Submit: 1025  Solved: 359

[Submit][Status][Discuss]

Description

给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。

Input

第一行输入三个正整数n,m,K,表示有n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci<=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。

Output

输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。

Sample Input

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

HINT

对于所有数据n<=30000,m<=60000,2<=K<=n。

数据保证最短路径树上至少存在一条长度为K的路径。

2016.12.7新加数据一组by - wyx-150137

mdzz刷的这几道题就这道最水(相对),虽然代码也不短,但是套路呀

点分套路题,具体点分套路请见:
普通套路 和  
一般套路
若想拓展点分树套路请见:
点分树套路

好了我们开始题解:
一共两问:
长度为k的最长路径  和  长度为k的权值长为最长权值的路径条数
千万要读清第二问!!!
第二问也要求长度为k!!!
以开始以为第二问不限制长度,以为这题两问两个套路,实际上都是不满足前缀减法的 一般套路
辣么熟悉点分治套路的同学就可以随便切了,不熟悉的建议先切上面普通套路 和一般套路这两道题

代码:

/**************************************************************
Problem: 4016
User: **********
Language: C++
Result: Accepted
Time:944 ms
Memory:29716 kb
****************************************************************/

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<cstdio>
#include<climits>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define N 100010
#define M 200020
#define inf 1<<26
#define pa pair<int,int>
#define lowbit(x) x&(-x)
using namespace std;
int read()
{
int x=0,f=1;char ch;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

int n,m,k,ans,ans1;

int head
,pos;
struct edge{int to,next,c;}e[M];
void add(int a,int b,int c)
{pos++;e[pos].to=b,e[pos].next=head[a],e[pos].c=c,head[a]=pos;}

queue<int>Q;bool vis
;int dis
;

vector<pa>G
;
void spfa()
{
for(int i=1;i<=n;i++)dis[i]=inf,vis[i]=0;
dis[1]=0,vis[1]=1;Q.push(1);
while(!Q.empty())
{
int u=Q.front();Q.pop();vis[u]=0;
int size=G[u].size();
for(int j=0;j<size;j++)
{
pa v=G[u][j];
if(dis[v.first]>dis[u]+v.second)
{
dis[v.first]=dis[u]+v.second;
if(!vis[v.first])
{
vis[v.first]=1;
Q.push(v.first);
}
}
}
}
}
void dfs(int u)
{
int size=G[u].size();vis[u]=1;
for(int i=0;i<size;i++)
{
int v=G[u][i].first,c=G[u][i].second;
if(vis[v]||dis[v]!=dis[u]+c)
continue;
add(u,v,c);add(v,u,c);dfs(v);
}
}

int size
,sum,f
,rt;
void find_root(int u,int fa)
{
size[u]=1,f[u]=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(vis[v]||v==fa)continue;
find_root(v,u);size[u]+=size[v];
f[u]=max(size[v],f[u]);
}f[u]=max(f[u],sum-size[u]);
if(f[rt]>f[u])rt=u;
}

struct node{int w,num;}d
,p
;
int tot,t[N<<4][2],s[N<<4],all;

void get_dep(int u,int fa)
{
p[++tot]=d[u];
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa||vis[v])continue;
d[v].num=d[u].num+1;
d[v].w=d[u].w+e[i].c;
get_dep(v,u);
}
}
void cal(int u,int nowl,int nown)
{
d[u].w=nowl,d[u].num=nown;
tot=0;get_dep(u,0);
for(int i=1;i<=tot;i++)
if(p[i].num<k)
{
int tmp=p[i].w+t[k-p[i].num][0];
if(tmp>ans)ans=tmp,ans1=t[k-p[i].num][1];
else if(tmp==ans)ans1+=t[k-p[i].num][1];
}
else if(p[i].num==k)
{
if(p[i].w>ans)ans=p[i].w,ans1=1;
else if(p[i].w==ans)ans1++;
}
for(int i=1;i<=tot;i++)
if(p[i].num<=k)
{
if(p[i].w>t[p[i].num][0])
t[p[i].num][0]=p[i].w,t[p[i].num][1]=1;
else if(p[i].w==t[p[i].num][0])t[p[i].num][1]++;
s[++all]=p[i].num;
}
}
void work(int u)
{
vis[u]=1;all=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(vis[v])continue;
cal(v,e[i].c,1);
}for(int i=1;i<=all;i++)t[s[i]][0]=t[s[i]][1]=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(vis[v])continue;
sum=size[v],rt=0;
find_root(v,0);work(rt);
}
}

void find_dep(int u,int fa)
{
p[++tot]=d[u];s[++all]=d[u].w;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa||vis[v])continue;
d[v].w=d[u].w+e[i].c;
find_dep(v,u);
}
}

int main()
{
// freopen("in.txt","r",stdin);
// freopen("my.txt","w",stdout);
n=read(),m=read(),k=read()-1;
for(int i=1;i<=m;i++)
{
int a=read(),b=read(),c=read();
G[a].push_back(make_pair(b,c));
G[b].push_back(make_pair(a,c));
}
for(int i=1;i<=n;i++)
sort(G[i].begin(),G[i].end());
spfa();for(int i=1;i<=n;i++)vis[i]=0;
dfs(1);for(int i=1;i<=n;i++)vis[i]=0;
sum=f[0]=n,rt=0;find_root(1,0);work(rt);
memset(vis,0,sizeof(vis));
printf("%d %d\n",ans,ans1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: