bzoj 4016: [FJOI2014]最短路径树问题 最短路+点分治
2017-10-18 20:53
671 查看
题意
给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。
n<=30000,m<=60000,2<=K<=n。
分析
首先要把最短路树求出来。这个的话可以先把原图的最短路DAG求出来,然后从1开始,每次沿着字典序最小的边跑,就可以得到最短路树。那后就是个sb点分治了。
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=30005; const int inf=1000000000; int n,m,k,cnt,last ,tot,ans,ans1,dis ,now,t ,size ,mx ,root,s ; bool vis ; pair<int,int> a ; pair<int,pair<int,int> > tmp[N*2]; struct edge{int to,next,w,use;}e[N*4]; priority_queue<pair<int,int> > que; int read() { int x=0,f=1;char ch=getchar(); 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; } void addedge(int u,int v,int w) { e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt; e[++cnt].to=u;e[cnt].w=w;e[cnt].next=last[v];last[v]=cnt; } void dfs(int x) { vis[x]=1; for (int i=last[x];i;i=e[i].next) if (e[i].use==1&&!vis[e[i].to]) e[i].use=e[i^1].use=2,dfs(e[i].to); } void dij() { for (int i=2;i<=n;i++) dis[i]=inf; que.push(make_pair(0,1)); while (!que.empty()) { pair<int,int> u=que.top();que.pop(); while (!que.empty()&&vis[u.second]) u=que.top(),que.pop(); if (vis[u.second]) break; int x=u.second;vis[x]=1; for (int i=last[x];i;i=e[i].next) if (!vis[e[i].to]&&dis[x]+e[i].w<dis[e[i].to]) { dis[e[i].to]=dis[x]+e[i].w; que.push(make_pair(-dis[e[i].to],e[i].to)); } } for (int i=2;i<=cnt;i++) { int x=e[i^1].to,y=e[i].to; if (dis[x]+e[i].w==dis[y]) e[i].use=1; } memset(vis,0,sizeof(vis)); dfs(1); } void get_root(int x,int fa) { size[x]=1;mx[x]=0; for (int i=last[x];i;i=e[i].next) { if (e[i].use<2||vis[e[i].to]||e[i].to==fa) continue; get_root(e[i].to,x); size[x]+=size[e[i].to]; mx[x]=max(mx[x],size[e[i].to]); } mx[x]=max(mx[x],tot-size[x]); if (!root||mx[x]<mx[root]) root=x; } void get_w(int x,int len,int dis,int fa) { if (len<=k) a[++now]=make_pair(dis,len); size[x]=1; for (int i=last[x];i;i=e[i].next) { if (e[i].use<2||vis[e[i].to]||e[i].to==fa) continue; get_w(e[i].to,len+1,dis+e[i].w,x); size[x]+=size[e[i].to]; } } void solve(int x) { vis[x]=1; now=0; for (int i=last[x];i;i=e[i].next) { if (e[i].use<2||vis[e[i].to]) continue; int tmp=now; get_w(e[i].to,1,e[i].w,x); for (int j=tmp+1;j<=now;j++) { int w=a[j].first,len=a[j].second; if (t[k-len]>-1) { if (w+t[k-len]>ans) ans=w+t[k-len],ans1=s[k-len]; else if (w+t[k-len]==ans) ans1+=s[k-len]; } } for (int j=tmp+1;j<=now;j++) { int w=a[j].first,len=a[j].second; if (w>t[len]) t[len]=w,s[len]=1; else if (w==t[len]) s[len]++; } } while (now) t[a[now].second]=-1,s[a[now].second]=0,now--; for (int i=last[x];i;i=e[i].next) { if (e[i].use<2||vis[e[i].to]) continue; root=0;tot=size[e[i].to]; get_root(e[i].to,x); solve(root); } } int main() { n=read();m=read();k=read()-1;cnt=1; for (int i=1;i<=m;i++) { int x=read(),y=read(),z=read(); tmp[i]=make_pair(x,make_pair(y,z)); } sort(tmp+1,tmp+m+1); for (int i=m;i>=1;i--) addedge(tmp[i].first,tmp[i].second.first,tmp[i].second.second); dij(); memset(vis,0,sizeof(vis)); tot=n;root=0; get_root(1,0); for (int i=1;i<=k;i++) t[i]=-1; s[0]=1; solve(root); printf("%d %d",ans,ans1); return 0; }
相关文章推荐
- BZOJ 4016: [FJOI2014]最短路径树问题( 最短路 + 点分治 )
- BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治
- 【BZOJ4016】[FJOI2014]最短路径树问题 最短路径树+点分治
- 【bzoj4016】[FJOI2014]最短路径树问题 堆优化Dijkstra+DFS树+树的点分治
- [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)
- bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)
- 【BZOJ4016】【FJOI2014】 最短路径树问题 树的点分治
- [bzoj 4016] [Fjoi 2014] 最短路径树问题
- bzoj 4016: [FJOI2014]最短路径树问题
- 【BZOJ 4016】[FJOI2014]最短路径树问题
- BZOJ 4016 最短路径树问题 [最短路+树分治]
- bzoj 4016: [FJOI2014]最短路径树问题
- 【BZOJ 4016】[FJOI2014]最短路径树问题
- 【BZOJ 4016】 [FJOI2014]最短路径树问题
- BZOJ 4016: [FJOI2014]最短路径树问题
- BZOJ 4016: [FJOI2014]最短路径树问题
- 【bzoj4016】 FJOI2014—最短路径树问题
- 4016: [FJOI2014]最短路径树问题 点分治
- 【BZOJ-4016】最短路径树问题 Dijkstra + 点分治
- 4016: [FJOI2014]最短路径树问题