[bzoj 4016] [Fjoi 2014] 最短路径树问题
来源:互联网 发布:大学生创业成功率数据 编辑:程序博客网 时间:2024/06/08 06:27
题目在这里
有生之年参加的第一次省选,当时太年轻太弱又碰到3道丧病题果断爆零了。(虽然现在还是很弱)考场上以为这是一道树形dp,因为树上的题目除了dfs和dp外啥都不知道。。。。。
这题是点分治大裸题(我也只会写大裸题),然而我建树写了两节课。。。大致就是先从1号点跑一遍spfa或heap-dijkstra,显然满足dis[x]+w[x][y]==dis[y]的边在最短路径上。由于要求路径字典序最小,就优先走编号小的节点,这样一个点第一次被dfs到就一定是1到它的路径字典序最小了。
建完树之后直接点分治。记一下每棵子树的到重心刚好经过x个节点的路径的最大值_max[x],在记录一下这个最大值出现多少次,然后无脑码个150行注意一下就A了。
//最短路树+点分治 记录方案数 #include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <deque>#include <map>#include <set>#include <ctime>using namespace std;const int MAXN=30005,MAXM=60005,INF=1000000005;struct Edge{ int pre,from,to,cost,pos; bool flag;}E[MAXM*2],tmp[MAXM*2];int n,m,K,tot,fst[MAXN],dis[MAXN],depth[MAXN],size[MAXN],maxsize[MAXN],w[MAXN],_max[MAXN],nowmax[MAXN],st,ed,nowroot,cnt,amo[MAXN],nowamo[MAXN],son[MAXN],ans,sum;bool vis[MAXN]; struct Node{ int x,val; Node () {} Node(int _x,int _val) { x=_x,val=_val; } }; priority_queue<Node> H; bool operator < (Node a,Node b) { return a.val>b.val; }bool cmp1(const Edge &a,const Edge &b) { return (a.from<b.from) || (a.from==b.from && a.to<b.to); }bool cmp2(const Edge &a,const Edge &b) { return a.pos<b.pos; }int Get(){ char ch; int v=0; bool f=false; while (!isdigit(ch=getchar())) if (ch=='-') f=true; v=ch-48; while (isdigit(ch=getchar())) v=v*10+ch-48; if (f) return -v;else return v; }void add(int x,int y,int c,bool f){ E[++tot].pre=fst[x],fst[x]=tot,E[tot].from=x,E[tot].to=y,E[tot].cost=c,E[tot].flag=false; if (f) E[++tot].pre=fst[y],fst[y]=tot,E[tot].from=y,E[tot].to=x,E[tot].cost=c,E[tot].flag=false;}void Dijkstra() { for (int i=1;i<=n;i++) dis[i]=INF,vis[i]=false; dis[1]=0,H.push(Node(1,dis[1])),vis[1]=true; while (!H.empty()) { Node tmp=H.top(); H.pop(); int x=tmp.x; if (tmp.val!=dis[x]) continue; vis[x]=true; for (int i=fst[x];i;i=E[i].pre) { int y=E[i].to; if (!vis[y] && dis[x]+E[i].cost<dis[y]) dis[y]=dis[x]+E[i].cost,H.push(Node(y,dis[y])); } }}void dfs_init(int x) //建树 { vis[x]=true; for (int i=fst[x];i;i=E[i].pre) { int y=E[i].to; if (!vis[y] && dis[x]+E[i].cost==dis[y]) depth[y]=depth[x]+1,E[i].flag=true,dfs_init(y); }}void Build_Tree(){ for (int i=1;i<=tot;i++) tmp[i].from=E[i].from,tmp[i].to=E[i].to,tmp[i].cost=E[i].cost,tmp[i].pos=i; sort(tmp+1,tmp+1+tot,cmp1); for (int i=1;i<=n;i++) vis[i]=false,fst[i]=0; int ttot=tot; tot=0; for (int i=ttot;i>=1;i--) add(tmp[i].from,tmp[i].to,tmp[i].cost,0); depth[1]=1; dfs_init(1); for (int i=1;i<=tot;i++) tmp[i].from=E[i].from,tmp[i].to=E[i].to,tmp[i].cost=E[i].cost,tmp[i].flag=E[i].flag; for (int i=1;i<=n;i++) fst[i]=0,vis[i]=false; ttot=tot; tot=0; for (int i=1;i<=ttot;i++) if (tmp[i].flag) add(tmp[i].from,tmp[i].to,tmp[i].cost,1); maxsize[0]=MAXN; } void dfs_size(int x,int fa) //算出孩子数 { maxsize[x]=0,size[x]=1,cnt++; for (int i=fst[x];i;i=E[i].pre) { int y=E[i].to; if (y!=fa && !vis[y]) dfs_size(y,x),size[x]+=size[y],maxsize[x]=max(maxsize[x],size[y]); }}void dfs_root(int x,int fa) //找重心 { maxsize[x]=max(maxsize[x],cnt-size[x]); if (maxsize[x]<maxsize[nowroot]) nowroot=x; for (int i=fst[x];i;i=E[i].pre) { int y=E[i].to; if (y!=fa && !vis[y]) dfs_root(y,x); }}void modify(int &a,int b,int &c,int v) { if (b>a) a=b,c=v;else if (a==b) c+=v; }void dfs_work(int x,int fa) //暴力统计 { if (depth[x]>K) return; son[++tot]=x; int tmp=_max[K-depth[x]]+w[x]; modify(nowmax[depth[x]],w[x],nowamo[depth[x]],1); modify(ans,tmp,sum,amo[K-depth[x]]); for (int i=fst[x];i;i=E[i].pre) { int y=E[i].to; if (y!=fa && !vis[y]) w[y]=w[x]+E[i].cost,depth[y]=depth[x]+1,dfs_work(y,x); }} void work(int root) //计算路径经过x的答案 { vis[root]=true; w[root]=0,depth[root]=0; tot=0; for (int i=fst[root];i;i=E[i].pre) { int y=E[i].to; if (!vis[y]) { st=tot+1,depth[y]=1,w[y]=E[i].cost,dfs_work(y,-1),ed=tot; for (int j=st;j<=ed;j++) modify(_max[depth[son[j]]],nowmax[depth[son[j]]],amo[depth[son[j]]],nowamo[depth[son[j]]]), nowmax[depth[son[j]]]=0,nowamo[depth[son[j]]]=0; } } for (int i=1;i<=tot;i++) { if (depth[son[i]]==K) modify(ans,w[son[i]],sum,1); nowmax[depth[son[i]]]=_max[depth[son[i]]]=amo[depth[son[i]]]=nowamo[depth[son[i]]]=0; }}void dfs(int x,int fa) //最外层dfs { cnt=nowroot=0; int root=0; dfs_size(x,fa); dfs_root(x,fa); root=nowroot; work(root); for (int i=fst[root];i;i=E[i].pre) { int y=E[i].to; if (!vis[y]) dfs(y,root); }}int main(){ freopen("mindistree.in","r",stdin); freopen("mindistree.out","w",stdout); n=Get(),m=Get(),K=Get(); K--; int u,v,d; tot=0; for (int i=1;i<=m;i++) u=Get(),v=Get(),d=Get(),add(u,v,d,1); Dijkstra(); Build_Tree(); ans=sum=0; dfs(1,-1); printf("%d %d\n",ans,sum); return 0;}
0 0
- [bzoj 4016] [Fjoi 2014] 最短路径树问题
- 【BZOJ 4016】[FJOI2014]最短路径树问题
- bzoj 4016: [FJOI2014]最短路径树问题
- BZOJ 4016: [FJOI2014]最短路径树问题
- BZOJ 4016 最短路径树问题 [最短路+树分治]
- bzoj 4016: [FJOI2014]最短路径树问题 最短路+点分治
- 【bzoj 4016】[FJOI2014]最短路径树问题 树分治+树形dp
- 4016: [FJOI2014]最短路径树问题
- HYSBZ 4016最短路径树问题
- 4016: [FJOI2014]最短路径树问题
- 最短路径树问题
- 最短路径问题
- 最短路径问题
- 最短路径问题
- 最短路径问题
- 最短路径问题
- 最短路径问题
- 最短路径问题
- java 线程池介绍
- 在sourceinsight中添加快速注释 Ctrl+/
- 考研目标
- 【springmvc+mybatis项目实战】杰信商贸-1.项目背景
- 协议、代理
- [bzoj 4016] [Fjoi 2014] 最短路径树问题
- 第十五周“知原理”题目1
- 【springmvc+mybatis项目实战】杰信商贸-2.数据库配置
- 【C++】一道考察重载、覆盖、多态的题目
- Qt 在窗体中摆放窗口部件
- 2015.12.4
- 用VBScript写Linux脚本——SecureCRT与VBScript
- HDU 2844 Coins(多重背包【二进制优化】)
- java格式化输出 printf 例子