题目大意:略 传送门

硬是把两个题拼到了一起= =

$dijkstra$搜出单源最短路,然后$dfs$建树,如果$dis_{v}=dis_{u}+e.val$,说明这条边在最短路图内,然后像$NOIP2018 D2T1$那样的思路,贪心地选出当前节点的所有子节点里,未被访问过的编号最小的节点递归,回溯后重复此过程。可以用$vector$预处理出来,或者用堆= =。

然后就是很经典的点分治问题了

求出树上固定边数的最长链,类似于[IOI2011]Race这道题的思路,只不过是反着搞。每次选择一个重心为根,开个桶统计答案就行了

求固定长度链的个数。但这道题用桶可能会存不下,可以写$map$代替桶(不过数据里好像没有存不下的情况..)。

由于判定条件是二元的,一个是边数一个是长度,排序双指针不知道行不行

还有我把$vector$改成堆就过了是什么鬼

代码巨长巨恶心

 #include <map>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 30010
#define M1 1010
#define ll long long
#define inf 233333333
#define it map<node,int>::iterator
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int n,m,K;
struct Edge{
int to[N1<<],nxt[N1<<],val[N1<<],head[N1],cte;
void ae(int u,int v,int w)
{
cte++;to[cte]=v,val[cte]=w;
nxt[cte]=head[u],head[u]=cte;
}
}g,e;
namespace Build_Tree{
struct node{
int id,val;
friend bool operator < (const node &s1,const node &s2){
if(s1.val!=s2.val) return s1.val>s2.val;
return s1.id>s2.id;
}
};
int cmp(node s1,node s2){return s1.id<s2.id;}
int vis[N1],dis[N1];
void dijkstra()
{
memset(dis,0x3f,sizeof(dis));
priority_queue<node>q;
q.push((node){,}); dis[]=;
int j,u,v; node k;
while(!q.empty())
{
k=q.top(); q.pop(); u=k.id; if(vis[u]) continue; vis[u]=;
for(j=g.head[u];j;j=g.nxt[j])
{
v=g.to[j];
if(dis[v]>dis[u]+g.val[j])
dis[v]=dis[u]+g.val[j], q.push((node){v,dis[v]});
}
}
memset(vis,,sizeof(vis));
}
priority_queue<node>q[N1];
void dfs(int u)
{
vis[u]=; node k;
for(int j=g.head[u];j;j=g.nxt[j])
{
if(vis[g.to[j]]||dis[g.to[j]]!=dis[u]+g.val[j]) continue;
q[u].push((node){g.val[j],g.to[j]});
}
while(!q[u].empty())
{
k=q[u].top(); q[u].pop(); if(vis[k.val]) continue;
e.ae(u,k.val,k.id); e.ae(k.val,u,k.id);
dfs(k.val);
}
}
void Main()
{
dijkstra();
dfs();
}
};
int sz[N1],ms[N1],use[N1],tsz,G;
void gra(int u,int dad)
{
sz[u]=; ms[u]=;
for(int j=e.head[u];j;j=e.nxt[j])
{
if(use[e.to[j]]||e.to[j]==dad) continue;
gra(e.to[j],u);
sz[u]+=sz[e.to[j]]; ms[u]=max(ms[u],sz[e.to[j]]);
}
ms[u]=max(ms[u],tsz-sz[u]);
if(ms[u]<ms[G]) G=u;
} int ma[N1],q[N1],eq,tq[N1],et,dep[N1],dis[N1]; namespace Find_ma{
int ans;
void dfs(int u,int dad)
{
if(dep[u]>K) return; tq[++et]=u;
for(int j=e.head[u];j;j=e.nxt[j])
{
if(use[e.to[j]]||e.to[j]==dad) continue;
dep[e.to[j]]=dep[u]+; dis[e.to[j]]=dis[u]+e.val[j];
dfs(e.to[j],u);
}
}
void calc(int u)
{
int i,j,x;
dep[u]=; ma[]=;
for(j=e.head[u];j;j=e.nxt[j])
{
if(use[e.to[j]]) continue;
dep[e.to[j]]=; dis[e.to[j]]=e.val[j];
dfs(e.to[j],u);
for(i=;i<=et;i++)
{
x=tq[i];
ans=max(ans,ma[K-dep[x]]+dis[x]);
}
while(et)
{
x=tq[et--]; q[++eq]=dep[x];
ma[dep[x]]=max(ma[dep[x]],dis[x]);
}
}
while(eq) ma[q[eq--]]=-inf;
}
void main_dfs(int u)
{
int j,v; use[u]=; calc(u);
for(j=e.head[u];j;j=e.nxt[j])
{
v=e.to[j]; if(use[v]) continue;
tsz=sz[v]; G=; gra(v,u);
main_dfs(G);
}
}
void solve()
{
ms[]=tsz=n; G=; gra(,-); gra(G,-);
for(int i=;i<=n;i++) ma[i]=-inf;
main_dfs(G);
}
}; namespace Count{ struct node{
int dis,dep;
friend bool operator < (const node &s1,const node &s2)
{
if(s1.dis!=s2.dis) return s1.dis<s2.dis;
return s1.dep<s2.dep;
}
};
int M,ans; map<node,int>mp;
void dfs(int u,int dad)
{
if(dis[u]>M||dep[u]>K) return;
mp[(node){dis[u],dep[u]}]++;
for(int j=e.head[u];j;j=e.nxt[j])
{
if(use[e.to[j]]||e.to[j]==dad) continue;
dep[e.to[j]]=dep[u]+; dis[e.to[j]]=dis[u]+e.val[j];
dfs(e.to[j],u);
}
}
int calc(int u)
{
int ret=; node k,t; mp.clear(); dfs(u,-);
for(it i=mp.begin();i!=mp.end();i++)
{
k=i->first; t=(node){M-k.dis,K-k.dep};
if(mp.find(t)==mp.end()) continue;
if(k.dis==t.dis&&k.dep==t.dep) ret+=(i->second)*((i->second)-);
else ret+=mp[t]*(i->second);
}
return ret/;
}
void main_dfs(int u)
{
int j,v; use[u]=; dis[u]=; dep[u]=; ans+=calc(u);
for(j=e.head[u];j;j=e.nxt[j])
{
v=e.to[j]; if(use[v]) continue;
ans-=calc(v); tsz=sz[v]; G=; gra(v,u);
main_dfs(G);
}
}
void solve()
{
M=Find_ma::ans;
memset(use,,sizeof(use));
ms[]=tsz=n; G=; gra(,-); gra(G,-);
main_dfs(G);
}
}; int main()
{
//freopen("t2.in","r",stdin);
int i,x,y,z;
scanf("%d%d%d",&n,&m,&K); K--;
for(i=;i<=m;i++)
{
x=gint(),y=gint(),z=gint();
g.ae(x,y,z),g.ae(y,x,z);
}
Build_Tree::Main();
Find_ma::solve();
Count::solve();
printf("%d %d\n",Find_ma::ans,Count::ans);
return ;
}
/*
6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1 3 4 7 6 4
1 2 2
1 3 1
2 4 4
2 5 3
3 6 2
5 7 2 9 1
*/

BZOJ 4016 [FJOI2014]最短路径树问题 (贪心+点分治)的更多相关文章

  1. bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)

    4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 426  Solved: 147[Submit][Stat ...

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

    bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...

  3. BZOJ 4016: [FJOI2014]最短路径树问题( 最短路 + 点分治 )

    先跑出最短路的图, 然后对于每个点按照序号从小到大访问孩子, 就可以搞出符合题目的树了. 然后就是经典的点分治做法了. 时间复杂度O(M log N + N log N) -------------- ...

  4. [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)

    4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 1796  Solved: 625[Submit][Sta ...

  5. 【BZOJ4016】[FJOI2014]最短路径树问题(点分治,最短路)

    [BZOJ4016][FJOI2014]最短路径树问题(点分治,最短路) 题面 BZOJ 洛谷 题解 首先把最短路径树给构建出来,然后直接点分治就行了. 这个东西似乎也可以长链剖分,然而没有必要. # ...

  6. luogu 2993 [FJOI2014]最短路径树问题 Dijkstra+点分治

    挺简单的,但是给人一种把两个问题强行弄到一起的感觉. 十分不好写. Code: #include <queue> #include <cstdio> #include < ...

  7. 【BZOJ-4016】最短路径树问题 Dijkstra + 点分治

    4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 1092  Solved: 383[Submit][Sta ...

  8. 【BZOJ4016】[FJOI2014]最短路径树问题

    [BZOJ4016][FJOI2014]最短路径树问题 题面 bzoj 洛谷 题解 虽然调了蛮久,但是思路还是蛮简单的2333 把最短路径树构出来,然后点分治就好啦 ps:如果树构萎了,这组数据可以卡 ...

  9. [BZOJ4016][FJOI2014]最短路径树问题

    [BZOJ4016][FJOI2014]最短路径树问题 试题描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长 ...

随机推荐

  1. 30分钟精通React今年最劲爆的新特性——React Hooks

    你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周 ...

  2. github发布博客

    创建github项目:  名字为:{{你的帐号}}.github.io clone项目,创建并提交推送一个index页面 如: <!DOCTYPE html> <html> & ...

  3. 敏捷开发-srcum

    SCRUM框架包括3个角色.3个工件.5个活动.5个价值 3个角色 1.产品负责人(Product Owner) 2.Scrum Master 3.Scrum团队 3个工具 1.Product Bac ...

  4. C# 知识点集合

    1.一个Visual studio软件进程只能打开一个程序集,但是一个程序集可以加载多个项目,通过程序集的添加功能可以实现. 2.F11单步调试,F10跨程序调试(一般用不到) 3.VS如何快速的切换 ...

  5. Oracle-定时任务

    PLSQL->新建->命令行窗口 --存储过程 create or replace procedure prd_remove_error_data AS BEGIN UPDATE rpt_ ...

  6. Java n个线程轮流打印数字的问题

    一. 实现两个线程.轮流打印出数字.例如以下: bThread --> 10 aThread --> 9 bThread --> 8 aThread --> 7 bThread ...

  7. C语言:一个涉及指针函数返回值与printf乱码、内存堆栈的经典案例

    一个奇怪的C语言问题,涉及到指针.数组.堆栈.以及printf.以下实现: 整数向字符串的转换,返回字符串指针,并在main函数中调用printf显示. #include<stdio.h> ...

  8. Oracle配置网络服务

    对于Oracle来说.不管是连接本地数据库还是远程连接server数据库,都须要在本机配置网络服务才可连接. 大家可能不明确为什么. 先拿SqlServer来说.SqlServer在连接数据库的时候仅 ...

  9. 读配置文件能够保持顺序的 Java Properties 类

    序 前几天,公司项目中有一个需求是读取配置文件的.并且最好可以保证载入到内存中的顺序可以和配置文件里的顺序一致,可是.假设使用 jdk 中提供的 Properties 类的话,读取配置文件后.载入到内 ...

  10. ZOJ 3633 Alice's present RMQ

     Alice's present Description As a doll master, Alice owns a wide range of dolls, and each of them ha ...