HDU4871 Shortest-path tree(树分治)
好久没做过树分治的题了,对上一次做是在南京赛里跪了一道很裸的树分治题后学的一道,多校的时候没有看这道题,哪怕看了感觉也看不出来是树分治,看出题人给了解题报告里写了树分治就做一下好了。
题意其实就是给你一个图,然后让你转换成一棵树,这棵树满足的是根节点1到其余各点的距离都是图里的最短距离,而且为了保证这棵树的唯一性,路径也必须是最小的。转化成树的方法其实就是跑一次spfa。spfa的时候记下所有到这个的前驱的边,然后这些边集反向的边补上就是构成所有最短路的边。然后在这些边上跑一次dfs,跑前将边按照到达点的序号由小到大排序,注意dfs搜的下一个点的距离必须是最短的才搜,不然的话搜出来的图就是不对的,比划一下题目给的样例就知道了。
至此图的部分转化完了,剩下的就是求一个图里包含了k个点的路径的最长距离,以及有多少条,相似的问题还有有多少条路径的乘积=k,有多少条路径的和>k,有多少条路径的乘积是完全立方数。。。做法就是典型的树分治。
树分治在《挑战程序设计竞赛》这本书上有一个很好的框架可以直接抄,我就直接拿来用了。具体的做法是找出重心,对重心外的部分递归求解,合并的时候枚举到重心的所有路径,枚举的时候可以用一个全局的map ds记录当前到达这个点的所有情况,然后用一个tds去枚举新的部分的路径,然后通过ds和tds更新答案,更新完后将tds的内容加进去ds。下面贴一记代码好了
#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
using namespace std; #define ll long long
#define maxn 31000
#define maxm 61000
#define MP make_pair struct Edge{
int v, w;
Edge(int vi, int wi) :v(vi), w(wi){}
Edge(){}
bool operator < (const Edge & b) const{
return v < b.v;
}
}; vector<Edge> G[maxn];
vector<Edge> E[maxn];
vector<Edge> EE[maxn];
vector<Edge> T[maxn]; int n, m, k; int d[maxn];
int dx[maxn];
bool in[maxn]; void dfs(int u,int dis)
{
in[u] = true; dx[u] = dis;
if (dx[u] != d[u]) puts("fuck");
for (int i = 0; i < EE[u].size(); i++){
int v = EE[u][i].v, w = EE[u][i].w;
if (!in[v]&&w+dis==d[v]) {
T[u].push_back(Edge(v, w));
T[v].push_back(Edge(u, w));
dfs(v, w + dis);
}
}
} void spfa()
{
queue<int> que;
memset(in, 0, sizeof(in));
memset(d, 0x3f, sizeof(d));
d[1] = 0; in[1] = true; que.push(1);
while (!que.empty()){
int u = que.front(); que.pop(); in[u] = false;
for (int i = 0; i < G[u].size(); i++){
int v = G[u][i].v, w = G[u][i].w;
if (d[u] + w < d[v]){
d[v] = d[u] + w;
if (!in[v]) {
in[v] = true; que.push(v);
}
E[v].clear(); E[v].push_back(Edge(u, w));
}
else if (d[u] + w == d[v]){
E[v].push_back(Edge(u, w));
}
}
}
for (int i = 1; i <= n; i++){
for (int j = 0; j < E[i].size(); j++){
EE[E[i][j].v].push_back(Edge(i, E[i][j].w));
EE[i].push_back(E[i][j]);
}
}
for (int i = 1; i <= n; i++) sort(EE[i].begin(), EE[i].end());
memset(in, 0, sizeof(in));
memset(dx, 0x3f, sizeof(dx));
dfs(1,0);
} bool centroid[maxn];
int ssize[maxn]; int compute_subtree_size(int v, int p){
int c = 1;
for (int i = 0; i < T[v].size(); i++){
int w = T[v][i].v;
if (w == p || centroid[w]) continue;
c += compute_subtree_size(w, v);
}
ssize[v] = c;
return c;
} pair<int, int> search_centroid(int v, int p, int t){
pair<int, int> res = MP(INT_MAX, -1);
int s = 1, m = 0;
for (int i = 0; i < T[v].size(); i++){
int w = T[v][i].v;
if (w == p || centroid[w]) continue; res = min(res, search_centroid(w, v, t)); m = max(m, ssize[w]);
s += ssize[w];
}
m = max(m, t - s);
res = min(res, MP(m, v));
return res;
} map<int, pair<int, int> > ds;
map<int, pair<int, int> > tds;
map<int, pair<int, int> >::iterator it;
map<int, pair<int, int> >::iterator itt;
// pass kk points, distant is dis
void enumerate(int v, int p, int kk, int dis, map<int, pair<int, int> > &tds)
{
if (kk > k) return;
it = tds.find(kk);
if (it!=tds.end()){
if (it->second.first == dis) {
it->second.second += 1;
}
else if(it->second.first<dis){
tds.erase(it);
tds.insert(MP(kk, MP(dis, 1)));
}
}
else{
tds.insert(MP(kk, MP(dis, 1)));
}
for (int i = 0; i < T[v].size(); i++){
int w = T[v][i].v;
if (w == p || centroid[w]) continue;
enumerate(w, v, kk + 1, dis + T[v][i].w, tds);
}
} ll ans, num; void solve(int v)
{
compute_subtree_size(v, -1);
int s = search_centroid(v, -1, ssize[v]).second;
centroid[s] = true;
for (int i = 0; i < T[s].size(); i++){
if (centroid[T[s][i].v]) continue;
solve(T[s][i].v);
}
ds.clear();
ds.insert(MP(1, MP(0, 1)));
for (int i = 0; i < T[s].size(); i++){
if (centroid[T[s][i].v]) continue;
tds.clear();
enumerate(T[s][i].v, s, 1, T[s][i].w, tds);
it = tds.begin();
while (it != tds.end()){
int kk = it->first;
if (ds.count(k - kk)){
itt = ds.find(k - kk);
int ldis = it->second.first + itt->second.first;
if (ldis>ans) {
ans = ldis; num = it->second.second*itt->second.second;
}
else if (ldis == ans){
num += it->second.second*itt->second.second;
}
}
++it;
}
it = tds.begin();
while (it != tds.end()){
int kk = it->first + 1;
if (ds.count(kk)){
itt = ds.find(kk);
if (it->second.first > itt->second.first){
ds.erase(itt);
ds.insert(MP(kk, it->second));
}
else if (it->second.first == itt->second.first) itt->second.second += it->second.second;
}
else{
ds.insert(MP(kk, it->second));
}
++it;
}
}
centroid[s] = false;
} int main()
{
int TE; cin >> TE;
while (TE--){
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i <= n; i++) {
G[i].clear(); E[i].clear(); EE[i].clear(); T[i].clear();
}
int ui, vi, wi;
for (int i = 0; i < m; i++){
scanf("%d%d%d", &ui, &vi, &wi);
G[ui].push_back(Edge(vi, wi));
G[vi].push_back(Edge(ui, wi));
}
spfa();
ans = 0, num = 0;
solve(1);
cout << ans << " " << num << endl;
}
return 0;
}
HDU4871 Shortest-path tree(树分治)的更多相关文章
- 【BZOJ-1468】Tree 树分治
1468: Tree Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1025 Solved: 534[Submit][Status][Discuss] ...
- HDU 4812 D Tree 树分治+逆元处理
D Tree Problem Description There is a skyscraping tree standing on the playground of Nanjing Unive ...
- POJ 1741 Tree 树分治
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1 ...
- POJ 1741.Tree 树分治 树形dp 树上点对
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 24258 Accepted: 8062 Description ...
- poj 1744 tree 树分治
Tree Time Limit: 1000MS Memory Limit: 30000K Description Give a tree with n vertices,each ed ...
- HDU 4812 D Tree 树分治
题意: 给出一棵树,每个节点上有个权值.要找到一对字典序最小的点对\((u, v)(u < v)\),使得路径\(u \to v\)上所有节点权值的乘积模\(10^6 + 3\)的值为\(k\) ...
- HDU4670 Cube number on a tree 树分治
人生的第一道树分治,要是早点学我南京赛就不用那么挫了,树分治的思路其实很简单,就是对子树找到一个重心(Centroid),实现重心分解,然后递归的解决分开后的树的子问题,关键是合并,当要合并跨过重心的 ...
- CodeChef - PRIMEDST Prime Distance On Tree 树分治 + FFT
Prime Distance On Tree Problem description. You are given a tree. If we select 2 distinct nodes unif ...
- POJ1741 Tree 树分治模板
http://poj.org/problem?id=1741 题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数. dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...
随机推荐
- Python学习教程(learning Python)--1.4 Python数据处理基础
本节主要讨论数据操作及运算符等基础知识,熟悉C语言相关知识的读者请跳过此节. 在高级语言编程过程中,有了数据以后通常要对数据进行相应的数据处理,加.减.乘.除等基本运算,不难理解. 在Python里 ...
- Html5 Canvas一个简单的画笔例子
相比了下Qt quick的canvas和HTML5的canvas,发现HTML5 Canvas在同样绘制绘制操作下性能比Qt的canvas强很多,附上一个HTML5 canvas画笔一例子 var D ...
- OC编写使用调试器
OC编写使用调试器 编写代码免不了,Bug.那么Debug就是程序员的必备技能了.本文和大家一起探讨,如何在应用开发编写代码过程中,使用日志项消息:以及使用动作.条件.迭代控制增强断点. 记录信息 在 ...
- hdu 1026 Ignatius and the Princess I
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1026 Ignatius and the Princess I Description The Prin ...
- 初识java之Mina(一)
Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于 TCP/IP.UDP/IP协议栈的通信框架(当然,也可以提供 JAVA 对象的序列化服务.虚拟机管道通信服务等) ...
- SQL Server 2008 没有可用于 charge_sys_Log.LDF 的编辑器
因为上网问题重新装了系统.今天在整 SQL Server 的时候出现了这样一个问题. 因为之前装 SQL Server 的时候没有遇到过这种情况,感觉很新奇.所以详细的记录一下,希望对别人能有一定 ...
- 微软职位内部推荐-Sr SDE
微软近期Open的职位: MSN reaches nearly half a billion people across the globe where we are the #1 portal in ...
- 团队作业week3 团队成员规划
划分角色:PM:黄剑锟 Dev:顾泽鹏 周辰光 孙时 Test:龚少波 赵骞 彭佟 团队贡献分的分配方法:设定两个考察方面,分别为工作量和任务难度,每个人的个人单次得分为该次任务的 工作量(最高10分 ...
- 我给女朋友讲编程html系列(3) --html中的超链接标签-a标签 和 框架frame与框架集frameset
我们浏览网页的时候,当单击某段文字或图片时,就会打开一个新的网页,这里面就使用了超链接. 就比如下图是一个导航类网页,当你单击某个链接就会打开新的网页. 比如,我拿我的qq空间“金河访谈”举例,新建一 ...
- android 开发 解码gif图片,获取每帧bitmap
环境:android 4.3 (注意对于android4.4版本解码出来不正确,除了第一帧正确外,其余的都是显示不同的地方) 通用版本见: android 开发对gif解码(适配android 4 ...