HDU4871 Shortest-path tree(點分治)
阿新 • • 發佈:2019-02-09
clr scan 路徑 spa 最長路 res 復雜度 mem for
題目
題面
大意是給你一個圖,要你構建出一棵最短路樹,再詢問經過k個點的最長路徑長度以及最長路徑條數。
思路
點分治。
點分治的思路是這樣的:
對於一個點\(x\)而言,對答案有影響的路徑要麽經過點\(x\)要麽不經過,利用這點進行分治。
點分治首先要找出一個重心。重心是指以該點為根所有的子樹中sz最大的最小。
然後,對於每一棵子樹進行處理,統計答案(點分治題目不同的地方就在這,其它都是板子)
之後再遞歸進重心的子樹中處理。
對於一個根來說,如果統計答案的復雜度是\(O(n)\),那麽總的復雜度就是\(O(nlogn)\).
代碼
#include<bits/stdc++.h> #define M 30005 #define clr(x,y) memset(x,y,sizeof(x)) using namespace std; int T,n,m,K; int g[M],tt; int ansa=0,ansc=0;//最長路,最長路的種數 struct Node{ int to,co; bool operator < (const Node& res) const{ return to<res.to; } }; vector<Node>G[M]; struct edge{ int nxt,to,co; }H[M<<1]; void add(int a,int b,int c){ H[++tt]=(edge){g[a],b,c}; g[a]=tt; } struct node{ int x,ds; bool operator < (const node& res) const{ return ds>res.ds; } }; priority_queue<node>Q; int dis[M]; bool vis[M]; void Dij(){ clr(dis,0x3f);clr(vis,0); dis[1]=0; Q.push((node){1,0}); while(!Q.empty()){ node e=Q.top();Q.pop(); if(vis[e.x])continue;vis[e.x]=1; for(int i=0;i<(int)G[e.x].size();i++){ int u=G[e.x][i].to,v=G[e.x][i].co; if(dis[u]>dis[e.x]+v){ dis[u]=dis[e.x]+v; Q.push((node){u,dis[u]}); } } } } bool solved[M]; int sz[M],ttot; void dfs(int x,int f,int ds){//構造樹 for(int i=0;i<(int)G[x].size();i++){ int u=G[x][i].to,v=G[x][i].co; if(u==f||vis[u]||ds+v>dis[u])continue; vis[u]=1; add(u,x,v);add(x,u,v); dfs(u,x,ds+v); } } int mi=1e9,zx=1; void dfs_zx(int x,int f){//尋找重心 sz[x]=1;int mm=0; for(int i=g[x];i;i=H[i].nxt){ int u=H[i].to; if(u==f||solved[u])continue; dfs_zx(u,x); sz[x]+=sz[u]; mm=max(mm,sz[u]); } mm=max(mm,ttot-sz[x]); if(mm<mi)mi=mm,zx=x; } void find_zx(int rt){ mi=1e9,zx=1; dfs_zx(rt,0); } void getans(int x,int y){ if(x>ansa)ansa=x,ansc=y; else if(x==ansa)ansc+=y; } int mx[M],mn[M]; int num[M],siz=0; void dfs_ans(int x,int f,int ds,int c){ dis[++siz]=ds;num[siz]=c; for(int i=g[x];i;i=H[i].nxt){ int u=H[i].to,v=H[i].co; if(solved[u]||u==f)continue; dfs_ans(u,x,ds+v,c+1); } } void solve(int rt){ find_zx(rt); solved[zx]=1; for(int i=0;i<=K;i++)mx[i]=mn[i]=0;mn[0]=1; for(int i=g[zx];i;i=H[i].nxt){ int u=H[i].to,v=H[i].co; if(solved[u])continue; siz=0; dfs_ans(u,zx,v,1); for(int j=1;j<=siz;j++){ if(num[j]>=K)continue; int tmp=K-1-num[j]; getans(mx[tmp]+dis[j],mn[tmp]); } for(int j=1;j<=siz;j++){ if(num[j]>=K)continue; if(dis[j]>mx[num[j]]){ mx[num[j]]=dis[j]; mn[num[j]]=1; } else if(dis[j]==mx[num[j]])mn[num[j]]++; } } ttot--; for(int i=g[zx];i;i=H[i].nxt){ int u=H[i].to; if(solved[u])continue; solve(u); } } int main(){ cin>>T; while(T--){ clr(g,0);clr(solved,0);tt=ansa=ansc=0; scanf("%d%d%d",&n,&m,&K);ttot=n; for(int i=1;i<=n;i++)G[i].clear(); for(int i=1,a,b,c;i<=m;i++){ scanf("%d%d%d",&a,&b,&c); G[a].push_back((Node){b,c}); G[b].push_back((Node){a,c}); } for(int i=1;i<=n;i++)sort(G[i].begin(),G[i].end()); Dij(); clr(vis,0);dfs(1,0,0); solve(1); printf("%d %d\n",ansa,ansc); } return 0; }
HDU4871 Shortest-path tree(點分治)