CTSC模拟题 树上的路径
Description
给定一棵\(N\)个结点的树,结点用正整数\(1 \dots N\)编号,每条边有一个正整数权值。用\(d(a, b)\)表示从结点\(a\)到结点\(b\)路径上经过边的权值和,其中要求\(a < b\)。将这\(\frac{N(N-1)}{2}\)个距离值从大到小排序,输出前\(M\)个距离值。
Input
第一行包含两个正整数\(N,M\)。
下面\(N − 1\)行,每行三个正整数\(a, b, c (a, b \le N, c \le 10,000)\),表示结点\(a\)和结点\(b\)间有一条权值为\(c\)的边相连。
Output
共\(M\)行,每行一个正整数,第\(i\)行表示排在第\(i\)个的距离值。
Sample Input
5 10
1 2 1
1 3 2
2 4 3
2 5 4
Sample Output
7
7
6
5
4
4
3
3
2
1
Hint
\(N \le 50000,M \le min(\frac{N(N-1)}{2},30,000)\)
点分治+K路归并。由于树上的每条路径必定经过一个重心,在进行点分治时我们可以枚举到所有的路径。将重心到每个点的距离按dfs序插入数组(可以把每次分治的结果都插入数组中,数组开\(O(NlogN)\))中。由于保证枚举的两个点不在一棵子数中,每个点对应的链在dfs数组中一定是段连续的区间,故可以采用超级钢琴的做法。代码如下:
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<set>
#include<vector>
using namespace std;
#define maxn (100010)
int N,M,next[maxn],toit[maxn],len[maxn],side[maxn],L,R,f[20][maxn*10],bit[maxn*10];
int cnt = 1,num,size[maxn],large[maxn],dis[maxn*10],best; bool vis[maxn];
struct node
{
int pos,l,r,mx,key;
friend inline bool operator <(const node &a,const node &b) { return a.key > b.key; }
};
vector <node> vec; multiset <node> S;
inline void add(int a,int b,int c) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; len[cnt] = c; }
inline void ins(int a,int b,int c) { add(a,b,c); add(b,a,c); }
inline void getroot(int now,int fa,int rest)
{
size[now] = 1; large[now] = 0;
for (int i = side[now];i;i = next[i])
{
if (toit[i] == fa||vis[toit[i]]) continue;
getroot(toit[i],now,rest);
size[now] += size[toit[i]];
large[now] = max(large[now],size[toit[i]]);
}
large[now] = max(large[now],rest-size[now]);
if (large[now] < large[best]) best = now;
}
inline int find_root(int now,int rest) { best = 0; getroot(now,0,rest); return best; }
inline void dfs(int now,int fa,int d)
{
dis[++cnt] = d; vec.push_back((node){cnt,L,R,0,0});
for (int i = side[now];i;i = next[i])
if (toit[i] != fa&&!vis[toit[i]])
dfs(toit[i],now,d+len[i]);
}
inline void cut(int now)
{
vis[now] = true; L = R = ++cnt;
for (int i = side[now];i;i = next[i])
{
if (vis[toit[i]]) continue;
dfs(toit[i],now,len[i]); R = cnt;
}
for (int i = side[now];i;i = next[i])
if (!vis[toit[i]]) cut(find_root(toit[i],size[toit[i]]));
}
inline int query(int l,int r)
{
int len = r-l+1,lg = bit[len];
if (dis[f[lg][l]] > dis[f[lg][r-(1<<lg)+1]]) return f[lg][l];
else return f[lg][r-(1<<lg)+1];
}
int main()
{
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%d %d",&N,&M);
for (int i = 1,a,b,c;i < N;++i) scanf("%d %d %d",&a,&b,&c),ins(a,b,c);
large[0] = 1<<30; cnt = 0; cut(find_root(1,N));
for (int i = 1;(1 << i) <= (cnt<<1);++i)
for (int j = (1<<(i-1));j <= (1<<i)-1&&j <= cnt;++j) bit[j] = i-1;
for (int i = 1;i <= cnt;++i) f[0][i] = i;
for (int i = 1;i <= bit[cnt];++i)
for (int j = 1;j+(1<<i)-1 <= cnt;++j)
{
if (dis[f[i-1][j]] > dis[f[i-1][j+(1<<(i-1))]]) f[i][j] = f[i-1][j];
else f[i][j] = f[i-1][j+(1<<(i-1))];
}
int nn = vec.size();
for (int i = 0;i < nn;++i)
{
node tmp = vec[i];
tmp.mx = query(tmp.l,tmp.r); tmp.key = dis[tmp.pos]+dis[tmp.mx];
S.insert(tmp);
}
for (int i = 1;i <= M;++i)
{
node now = *S.begin(); S.erase(S.begin());
printf("%d\n",now.key);
if (now.mx > now.l)
{
node tmp; tmp = now;
tmp.mx = query(tmp.l,tmp.mx-1);
tmp.key = dis[tmp.mx]+dis[tmp.pos];
tmp.r = now.mx-1; S.insert(tmp);
}
if (now.mx < now.r)
{
node tmp; tmp = now;
tmp.mx = query(tmp.mx+1,tmp.r);
tmp.key = dis[tmp.mx]+dis[tmp.pos];
tmp.l = now.mx+1; S.insert(tmp);
}
}
fclose(stdin); fclose(stdout);
return 0;
}
CTSC模拟题 树上的路径的更多相关文章
- 某模拟赛C题 树上路径统计 (点分治)
题意 给定一棵有n个节点的无根树,树上的每个点有一个非负整数点权.定义一条路径的价值为路径上的点权和-路径上的点权最大值. 给定参数P,我!=们想知道,有多少不同的树上简单路径,满足它的价值恰好是P的 ...
- 【BZOJ-3784】树上的路径 点分治 + ST + 堆
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 462 Solved: 153[Submit][Status][Discuss ...
- codevs 2756树上的路径
题意: 2756 树上的路径 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给出一棵树,求出最小的k,使得,且在树 ...
- 全国信息学奥林匹克联赛 ( NOIP2014) 复赛 模拟题 Day1 长乐一中
题目名称 正确答案 序列问题 长途旅行 英文名称 answer sequence travel 输入文件名 answer.in sequence.in travel.in 输出文件名 answer. ...
- bzoj 3784: 树上的路径 堆维护第k大
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 88 Solved: 27[Submit][Status][Discuss] ...
- ACdreamoj(1105)模拟题
题意:射一次激光最多能够攻击到几个敌人(因为激光非常强大,能够在击中敌人后穿过它,而瑶瑶自己的坦克因为有特殊装置,所以不会被激光击中.激光也会直接穿过它) . 表示此处为空地 * 表示此处为障碍(激光 ...
- NOIP模拟题 2017.7.3 - 模拟 - 贪心 - 记忆化搜索
直接暴力模拟,注意判数据结构为空时的取出操作. Code #include<iostream> #include<cstdio> #include<ctime> # ...
- NOIP模拟题汇总(加厚版)
\(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...
- 【BZOJ3784】树上的路径 点分治序+ST表
[BZOJ3784]树上的路径 Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a< ...
随机推荐
- LINUX kernel笔记系列 :IO块参数 图
Linux下,I/O处理的层次可分为4层: 系统调用层,应用程序使用系统调用指定读写哪个文件,文件偏移是多少 文件系统层,写文件时将用户态中的buffer拷贝到内核态下,并由cache缓存该部分数 ...
- Spring XD 1.1 M2 and 1.0.3 released---support kafka
官方地址:http://spring.io/blog/2014/12/23/spring-xd-1-1-m2-and-1-0-3-released On behalf of the Spring XD ...
- iOS 关于开发者证书:此证书的签发者无效的解决方案
备注:第二个步骤一定要进行,否则弄到吐血,还是现实签发者无效 ---------------------- 1,按照你那个链接下载,https://developer.apple.com/certif ...
- 3G/4G网卡使用
整体架构: pppd call option & ----------↓---------- option脚本(设置PPP连接) ----------↓---------- chat脚本(进行 ...
- Oracle 特殊字符模糊查询的方法
最近在写DAO层的时候,遇到一个问题,就是使用like进行模糊查询时,输入下划线,无法精确查到数据,而是返回所有的数据. 这让我很好奇,百度之后才发现,原来是因为有些特殊字符需要进行转义才可以进行查询 ...
- bootstap 滚动监听
---首先结合源代码介绍官网的说明 ---然后总结了使用滚动监听的几个步骤 ---最后给出一个简单的例子 ---关键的一点:整体有点零散和乱七八糟,辛苦你的思维和眼睛了,呵呵 ------------ ...
- [时间操作] C#DateFormat时间帮助类 (转载)
点击下载 DateFormat.rar 主要功能如下 返回每月的第一天和最后一天 看下面代码吧 /// <summary> /// 类说明:时间操作类 /// 编 码 人:苏飞 /// 联 ...
- [综合|基础|语法] 最新的皮肤帮助类 UI_Misc_Helper (转载)
using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; namespace ...
- Tomcat-java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory
好些天没弄java了,今天开MyEclipse,发现启动Tomcat的时候发错了,后来发现,报错如题. 解决方案是将 bin/tomcat-juli.jar 添加到add tomcat classpa ...
- 【基础】Oracle 表空间和数据文件
多个表空间的优势:1.能够将数据字典与用户数据分离出来,避免由于字典对象和用户对象保存在同一个数据文件中而产生的I/O冲突2.能够将回退数据与用户数据分离出来,避免由于硬盘损坏而导致永久性的数据丢失3 ...