HDU 4871 Shortest-path tree
先用dijkstra把最短路树建出来,然后就是树的质心分治了。
经过k个点的路径,要么全在子树上,要么经过根结点,因此可以分治。
如果分治的时候选点不好会变成O(n^2),比较极端的情况是比如树是一条链。
选择质心可以保证最大子树结点不超过n/2,每次递归至少减半,递归层数是O(logn)的。
找子树质心是O(n)的树形dp,枚举到根结点的路径是O(n)的。
把经过根节点并且路径上有c个结点的最长路径以及方案保存到一个map,对于一条新增的路径去查找k-c个点的路径,就可以更新答案了。
如果用的unorder_map,那么查找是O(1)的,因此分治复杂度是T(n) = 2*T(n/2) + O(n) ≈ O(nlogn)。
总体复杂度是O(mlogn + nlogn)
- /*********************************************************
- * ------------------ *
- * author AbyssFish *
- **********************************************************/
- #include<cstdio>
- #include<iostream>
- #include<string>
- #include<cstring>
- #include<queue>
- #include<vector>
- #include<stack>
- #include<map>
- #include<set>
- #include<algorithm>
- #include<cmath>
- #include<numeric>
- #include<climits>
- #include<unordered_map>
- using namespace std;
- const int maxn = +;
- const int maxm = *+;
- typedef long long ll;
- #define sInt 4
- int hd[maxn], nx[maxm], to[maxm], we[maxm], ec;
- #define eachedge int i = hd[u]; ~i; i = nx[i]
- void init_g(int n){ memset(hd+,0xff,sInt*n); ec = ; }
- void add_edge(int u,int v,int c)
- {
- to[ec] = v;
- we[ec] = c;
- nx[ec] = hd[u];
- hd[u] = ec++;
- }
- int n,m,k;
- int di[maxn], fe[maxn];
- typedef pair<int,int> pii;
- #define dist first
- #define ver second
- priority_queue<pii,vector<pii>,greater<pii> > q;
- void dijkstra()
- {
- memset(di+,0x3f,sInt*n);
- di[] = ; fe[] = -;
- q.push(pii(,));
- while(!q.empty()){
- pii x = q.top(); q.pop();
- if(x.dist != di[x.ver]) continue;
- int u = x.ver;
- for(int i = hd[u]; ~i; i = nx[i]){
- int v = to[i];
- if(di[v] > di[u] + we[i]){
- di[v] = di[u]+we[i];
- fe[v] = i;
- q.push(pii(di[v],v));
- }
- else if(di[v] == di[u] + we[i] && to[fe[v]^] > u){
- fe[v] = i;
- }
- }
- }
- }
- void rewrite(int u,int i)
- {
- nx[i] = hd[u];
- hd[u] = i;
- }
- void build_tree()
- {
- dijkstra();
- init_g(n);
- for(int v = ; v <= n; v++){
- int e = fe[v];
- int u = to[e^];
- rewrite(u,e);
- rewrite(v,e^);
- }
- }
- bool vis_c[maxn];
- int tr_sz[maxn];
- void cal_tr_sz(int u,int f)
- {
- int &c = tr_sz[u];
- c = ;
- for(eachedge){
- int v = to[i];
- if(v == f || vis_c[v]) continue;
- c += tr_sz[v];
- cal_tr_sz(v,u);
- }
- }
- int block_size;
- int best, centroid;
- void findCentroid(int u,int f)
- {
- int mx = ;
- for(eachedge){
- int v = to[i];
- if(v == f || vis_c[v]) continue;
- findCentroid(v,u);
- mx = max(mx, tr_sz[v]);
- }
- mx = max(mx,block_size-tr_sz[u]);
- if(best > mx){
- best = mx;
- centroid = u;
- }
- }
- typedef unordered_map<int,pii> cont;
- typedef cont::iterator con_it;
- //key 经过的点数,value(最长距离,方案数)
- cont prv;
- cont tmp;
- void update(cont &res,int c, const pii &np)
- {
- con_it it = res.find(c);
- if(it != res.end()){
- pii &p = it->second;
- if(p.dist == np.dist) p.ver += np.ver;
- else if(p.dist < np.dist) {
- p = np;
- }
- }
- else {
- res.insert(make_pair(c,np));
- }
- }
- void enum_path(int u,int f,int c,int d,cont &res)
- {
- if(c >= k) return;
- update(res,c,pii(d,));
- for(eachedge){
- int v = to[i];
- if(v == f || vis_c[v]) continue;
- enum_path(v,u,c+,d+we[i],res);
- }
- }
- int ans;
- ll cnt;
- void divide(int rt)
- {
- cal_tr_sz(rt,-);
- best = INT_MAX;
- block_size = tr_sz[rt];
- findCentroid(rt,-);
- int u = centroid;
- vis_c[u] = true;
- for(eachedge){
- if(!vis_c[to[i]]) divide(to[i]);
- }
- prv.clear();
- prv.insert(make_pair(,pii(,)));
- for(eachedge){
- if(vis_c[to[i]]) continue;
- tmp.clear();
- enum_path(to[i],u,,we[i],tmp);
- con_it it, it2;
- for(it = tmp.begin(); it != tmp.end(); it++){
- int c = it->first;
- pii &p = it->second;
- if((it2 = prv.find(k-c)) != prv.end()){
- ll dis = it2->second.dist + p.dist;
- if(dis > ans){
- ans = dis; cnt = p.ver * it2->second.ver;
- }
- else if(dis == ans) cnt += p.ver * it2->second.ver;
- }
- }
- for(it = tmp.begin(); it != tmp.end(); it++){
- int c = it->first+;
- update(prv,c,it->second);
- }
- }
- vis_c[u] = false;
- }
- void solve()
- {
- build_tree();
- ans = cnt = ;
- divide();
- printf("%d %lld\n",ans,cnt);
- }
- void init()
- {
- scanf("%d%d%d",&n,&m,&k);
- init_g(n);
- for(int i = ; i < m; i++){
- int a,b,c; scanf("%d%d%d",&a,&b,&c);
- add_edge(a,b,c);
- add_edge(b,a,c);
- }
- }
- //#define LOCAL
- int main()
- {
- #ifdef LOCAL
- freopen("in.txt","r",stdin);
- #endif
- int T; scanf("%d",&T);
- while(T--){
- init();
- solve();
- }
- return ;
- }
HDU 4871 Shortest-path tree的更多相关文章
- hdu 3631 Shortest Path(Floyd)
题目链接:pid=3631" style="font-size:18px">http://acm.hdu.edu.cn/showproblem.php?pid=36 ...
- HDU 5636 Shortest Path 暴力
Shortest Path 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 Description There is a path graph ...
- HDU 5636 Shortest Path(Floyed,枚举)
Shortest Path Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Tot ...
- HDU - 3631 Shortest Path(Floyd最短路)
Shortest Path Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u SubmitStat ...
- HDU - 4725_The Shortest Path in Nya Graph
The Shortest Path in Nya Graph Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...
- hdu 3631 Shortest Path
floyd算法好像很奇妙的样子.可以做到每次加入一个点再以这个点为中间点去更新最短路,效率是n*n. #include<cstdio> #include<cstring> #i ...
- HDU 5636 Shortest Path
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 题解: 1.暴力枚举: #include<cmath> #include<c ...
- HDU 5636 Shortest Path 分治+搜索剪枝
题意:bc round 74 分析(官方题解): 你可以选择分类讨论, 但是估计可能会写漏一些地方. 只要抽出新增边的端点作为关键点, 建立一个新图, 然后跑一遍floyd就好了. 复杂度大概O(6^ ...
- HDU 5636 Shortest Path(Floyd)
题目链接 HDU5636 n个点,其中编号相邻的两个点之间都有一条长度为1的边,然后除此之外还有3条长度为1的边. m个询问,每次询问求两个点之前的最短路. 我们把这三条边的6个点两两算最短路, 然 ...
- HDU 4479 Shortest path 带限制最短路
题意:给定一个图,求从1到N的递增边权的最短路. 解法:类似于bellman-ford思想,将所有的边先按照权值排一个序,然后依次将边加入进去更新,每条边只更新一次,为了保证得到的路径是边权递增的,每 ...
随机推荐
- 2.Servlet(一)
1.Servlet的编写.访问过程: (1)编写部署Servlet程序: 编写源文件->编译类文件->部署程序->运行->Servlet处理请求,返回响应. (2)Eclips ...
- HIVE sql取中文
select regexp_replace(str,'[^\\u4e00-\\u9fa5]','') as str1 from ( select 'test测试test' as str ) t ;
- 线程池ThreadPoolExecutor分析: 线程池是什么时候创建线程的,队列中的任务是什么时候取出来的?
带着几个问题进入源码分析: 1. 线程池是什么时候创建线程的? 2. 任务runnable task是先放到core到maxThread之间的线程,还是先放到队列? 3. 队列中的任务是什么时候取出来 ...
- my18_mysql中的几个超时时间
连接的超时时间 set global interactive_timeout=120;set global wait_timeout=120; 该连接指类似应用访问数据库的连接,可以是查询.DML.D ...
- vue混入(mixins)
混入(mixins)是一种分发vue组件中可复用功能的非常灵活的方式.混入对象可以包含任意组件选项. 当组件使用混入对象时,所以混入对象的选项将被混入该组件本身选项,当组件和混入对象含有同名选项时,这 ...
- MySQL · 引擎特性 · InnoDB index lock前世今生
http://mysql.taobao.org/monthly/2015/07/05/ MySQL · 引擎特性 · InnoDB index lock前世今生 前言 InnoDB并发过程中使用两类锁 ...
- (转)linux常见故障一:linux 文件系统变只读
linux常见故障一:linux 文件系统变只读 原文:https://www.cnblogs.com/ginvip/p/6375672.html 1. 重启系统看是否可以自动修复. 2. 使用fsc ...
- redis开机启动,有密码
#!/bin/sh # chkconfig: # description: Start and Stop redis REDISPORT= EXEC=/usr/local/redis/src/redi ...
- HDU 2121——Ice_cream’s world II——————【最小树形图、不定根】
Ice_cream’s world II Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64 ...
- AngularJS 学习(-)Hello world
早期的AngularJS使我们的前端开发模式发生很大的变化,基使用MVC. Model - html 模板:Controller - js脚本; Model 来自于Web API 或其他Service ...