传送门


强行二合一最为致命

第一问直接最短路+$DFS$解决

考虑第二问,与深度相关,可以考虑长链剖分。

设$f_{i,j}$表示长度为$i$,经过边数为$j$时的最大边权和,考虑到每一次从重儿子转移过来的时候,不仅要将$f$数组右移一格,还需要同时加上一个值。显然用线段树等数据结构额外维护是不现实的,我们考虑维护一个影响范围为整个$f_i$的加法标记$tag_i$,将$f_{i,0}$设置为$-tag_i$,每一次上传的时候把标记也一起上传,合并轻儿子、计算答案的时候将这个$tag$加上,就能够做到快速地维护了。

长链剖分代码比点分治还长……

 #include<bits/stdc++.h>
 #define P pair < int , int >
 #define int long long
 //This code is written by Itst
 using namespace std;

 inline int read(){
     ;
     ;
     char c = getchar();
     while(c != EOF && !isdigit(c)){
         if(c == '-')
             f = ;
         c = getchar();
     }
     while(c != EOF && isdigit(c)){
         a = (a << ) + (a << ) + (c ^ ');
         c = getchar();
     }
     return f ? -a : a;
 }

 ;
 vector < P > e[MAXN];
 struct edge{
     int end , upEd , w;
 }Ed[MAXN << ];
 ] , g[MAXN << ] , sz[MAXN] , tag[MAXN] , *dp[MAXN] , *cnt[MAXN];
 int *p1 = f , *p2 = g , N , M , K , cntEd , ans , times;
 priority_queue < P > q;
 bool vis[MAXN];

 inline void addEd(int a , int b , int c){
     Ed[++cntEd].end = b;
     Ed[cntEd].upEd = head[a];
     Ed[cntEd].w = c;
     head[a] = cntEd;
 }

 void Dijk(){
     q.push(P( , ));
     memset(dis , 0x3f , sizeof(dis));
     dis[] = ;
     while(!q.empty()){
         P t = q.top();
         q.pop();
         if(-t.first > dis[t.second])
             continue;
          ; i < sz[t.second] ; ++i)
             if(dis[e[t.second][i].first] > dis[t.second] + e[t.second][i].second){
                 dis[e[t.second][i].first] = dis[t.second] + e[t.second][i].second;
                 q.push(P(-dis[e[t.second][i].first] , e[t.second][i].first));
             }
     }
 }

 void create(int now){
     vis[now] = ;
      ; i < sz[now] ; ++i)
         if(!vis[e[now][i].first] && dis[e[now][i].first] == dis[now] + e[now][i].second){
             addEd(now , e[now][i].first , e[now][i].second);
             addEd(e[now][i].first , now , e[now][i].second);
             create(e[now][i].first);
         }
 }

 void dfs1(int now , int pre){
     md[now] = dep[now] = dep[pre] + ;
     for(int i = head[now] ; i ; i = Ed[i].upEd)
         if(!dep[Ed[i].end]){
             dfs1(Ed[i].end , now);
             if(md[Ed[i].end] > md[now]){
                 md[now] = md[Ed[i].end];
                 son[now] = Ed[i].end;
                 len[now] = Ed[i].w;
             }
         }
 }

 void dfs2(int now){
     if(son[now]){
         dp[son[now]] = dp[now] + ;
         cnt[son[now]] = cnt[now] + ;
         dfs2(son[now]);
         tag[now] = tag[son[now]] + len[now];
         dp[now][] = -tag[now];
     }
     cnt[now][] = ;
     if(ans < dp[now][K] + tag[now]){
         ans = dp[now][K] + tag[now];
         times = cnt[now][K];
     }
     else
         if(ans == dp[now][K] + tag[now])
             times += cnt[now][K];
     for(int i = head[now] ; i ; i = Ed[i].upEd)
          && Ed[i].end != son[now]){
             dp[Ed[i].end] = p1;
             cnt[Ed[i].end] = p2;
             p1 += (md[Ed[i].end] - dep[Ed[i].end] + ) << ;
             p2 += (md[Ed[i].end] - dep[Ed[i].end] + ) << ;
             dfs2(Ed[i].end);
              ; j <= md[Ed[i].end] - dep[Ed[i].end] && j <= K -  ; ++j)
                  - j)
                      - j] + Ed[i].w){
                         ans = tag[Ed[i].end] + dp[Ed[i].end][j] + tag[now] + dp[now][K -  - j] + Ed[i].w;
                         times = cnt[Ed[i].end][j] * cnt[now][K -  - j];
                     }
                     else
                          - j] + Ed[i].w)
                             times += cnt[Ed[i].end][j] * cnt[now][K -  - j];
              ; j <= md[Ed[i].end] - dep[Ed[i].end] +  && j <= K ; ++j)
                 ] + tag[Ed[i].end] + Ed[i].w - tag[now]){
                     dp[now][j] = dp[Ed[i].end][j - ] + tag[Ed[i].end] + Ed[i].w - tag[now];
                     cnt[now][j] = cnt[Ed[i].end][j - ];
                 }
                 else
                     ] + tag[Ed[i].end] + Ed[i].w - tag[now])
                         cnt[now][j] += cnt[Ed[i].end][j - ];
         }
 }

 signed main(){
 #ifndef ONLINE_JUDGE
     freopen("2993.in" , "r" , stdin);
     //freopen("2993.out" , "w" , stdout);
 #endif
     N = read();
     M = read();
     K = read() - ;
      ; i <= M ; ++i){
         int a = read() , b = read() , c = read();
         e[a].push_back(P(b , c));
         e[b].push_back(P(a , c));
         ++sz[a];
         ++sz[b];
     }
      ; i <= N ; ++i)
         sort(e[i].begin() , e[i].end());
     Dijk();
     create();
     dfs1( , );
     dp[] = p1;
     p1 += md[] << ;
     cnt[] = p2;
     p2 += md[] << ;
     dfs2();
     cout << ans << ' ' << times;
     ;
 }

Luogu2993 FJOI2014 最短路径树问题 最短路树、长链剖分的更多相关文章

  1. (持续更新)虚树,KD-Tree,长链剖分,后缀数组,后缀自动机

    真的就是讲课两天,吸收一个月呢! \(1.\)虚树 \(2.\)KD-Tree \(3.\)长链剖分 \(4.\)后缀数组 后缀数组 \(5.\)后缀自动机 后缀自动机

  2. [FJOI2014]最短路径树问题 长链剖分

    [FJOI2014]最短路径树问题 LG传送门 B站传送门 长链剖分练手好题. 如果你还不会长链剖分的基本操作,可以看看我的总结. 这题本来出的很没水平,就是dijkstra(反正我是不用SPFA)的 ...

  3. Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)

    题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...

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

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

  5. BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治

    BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择 ...

  6. 洛谷 [FJOI2014]最短路径树问题 解题报告

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

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

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

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

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

  9. 【BZOJ4016】[FJOI2014]最短路径树问题 最短路径树+点分治

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

随机推荐

  1. 【读书笔记】iOS-属性

    assign:简单的赋值. retain:赋值之后,会调用新的retain方法和旧值的release方法. copy:表示先将值拷贝一份,然后,将这个拷贝赋值给实例变量,这个修饰词只适用于实现了NSC ...

  2. Apktool(1)——Apktool的安装

    Apktool是google提供的apk的编译工具,有了它就可以做很多事情.比如获取apk的源码,apk汉化,对手机rom包做一些美化. 首先来看看apktool的安装(配置): 以下内容主要翻译字A ...

  3. (网页)HTML小技巧的一些小技巧

    转自CSDN: 1.怎样定义网页语言(字符集)?            在制作网页过程中,你首先要定义网页语言,以便访问者浏览器自动设置语言,而我们用所见即所得的HTML工具时,都没有注意到这个问题, ...

  4. OpenCV 的颜色空间转换

    # coding: utf-8 ''' 第13章主要介绍:颜色空间转换 ''' import cv2 import numpy as np ''' 经常用到的颜色空间转换是: BGR<-> ...

  5. 【Excel】SUMIF函数的兼容性

    兼容性非常强的两个函数 SUMIF() 说兼容性,当然得说SUMIF了. 来,我们先举个例子. 现有一个表格,算起来只有"科目划分"."发生额"两列内容,但是折 ...

  6. asp.net mvc项目使用spring.net发布到IIS后,在访问提示错误 Could not load type from string value 'DALMsSql.DBSessionFactory,DALMsSql'.

    asp.net mvc项目使用spring.net发布到IIS后,在访问提示错误 Could not load type from string value 'DALMsSql.DBSessionFa ...

  7. apply 和call 的区别,apply实用小技巧

    Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  8. Markdown图片存储解决方法-利用阿里云OSS

    我们在用markdown写一些博客或者文章的时候,常常需要引用一些图片,一般都是找一个免费的图床上传,然后复制图片链接在我们的markdown文章中.类似像这样: 存在的隐患 一般的免费图片托管网站有 ...

  9. (转)Python网络爬虫实战:世纪佳缘爬取近6万条数据

    又是一年双十一了,不知道从什么时候开始,双十一从“光棍节”变成了“双十一购物狂欢节”,最后一个属于单身狗的节日也成功被攻陷,成为了情侣们送礼物秀恩爱的节日. 翻着安静到死寂的聊天列表,我忽然惊醒,不行 ...

  10. swift 该死的派发机制--待完成

    swift 该死的派发机制 final static oc类型 多态类型 静态类型 动态函数  静态函数 nsobject: 1.缺省不再使用oc的动态派发机制: 2.可以使用nsobject暴露出来 ...