「CF150E」Freezing with Style「点分治」「单调队列」
题意
给定一颗带边权的树,求一条边数在\(L\)、\(R\)之间的路径,并使得路径上边权的中位数最大。输出一条可行路径的两个端点。这里若有偶数个数,中位数为中间靠右的那个。
\(n, L, R\leq 10^5\)
题解
看一眼是点分。然后发现中位数要二分,把\(\geq mid\)的权值设为\(1\),\(<mid\)的设为\(-1\),问题转换为找边权\(\geq 0\)的路径
易发现一个子树,每个深度存一个最大值就行
考虑怎么合并两个子树:假设之前子树答案是\(f\),\(f[d]\)表示深度为\(d\)的边权最大和。当前为\(g\)。
再考虑\(g[i]\)的时候,能与他配对的\(f\)实际上是区间\(f[L-i]\)到\(f[R-i]\),并且这个区间随着\(i\)增大而减小
用单调队列维护最大值即可。
注意子树要按深度从小到大排序,不然复杂度会被卡成平方!
时间复杂度\(O(n \log ^2n)\)。实现注意细节。
#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
const int INF = 1e7 + 10;
struct Edge { int v, w; };
int n, m, ans, ansu, ansv, L, R;
int size, rt, nowu, nowv, w[N], sz[N], tw[N];
vector<Edge> G[N];
bool vis[N];
void findrt(int u, int fa = 0) {
sz[u] = 1; w[u] = 0;
for(const Edge &e : G[u]) {
if(e.v != fa && !vis[e.v]) {
findrt(e.v, u);
sz[u] += sz[e.v];
w[u] = max(w[u], sz[e.v]);
}
}
w[u] = max(w[u], size - sz[u]);
if(!rt || w[u] < w[rt]) rt = u;
}
int d[N], cur_max, curd[N], fw[N];
void dfs0(int u, int fa = 0) {
cur_max = max(cur_max, d[u] = d[fa] + 1);
for(const Edge &e : G[u]) {
if(e.v != fa && !vis[e.v]) {
dfs0(e.v, u);
}
}
}
int st[N], top, low, f[N], g[N], fu[N], gu[N];
bool cmp(int x, int y) {
return curd[x] < curd[y];
}
void dfs(int u, int we, int fa = 0) {
if(g[d[u]] < we) {
g[d[u]] = we; gu[d[u]] = u;
}
for(const Edge &e : G[u]) if(e.v != fa && !vis[e.v]) {
dfs(e.v, we + (e.w >= low ? 1 : -1), u);
}
}
bool calc(int u, int mid) {
top = d[u] = 0;
for(const Edge &e : G[u]) if(!vis[e.v]) {
cur_max = 0; dfs0(e.v, u);
curd[e.v] = cur_max;
st[++ top] = e.v; fw[e.v] = e.w;
}
sort(st + 1, st + top + 1, cmp);
int ld = -1; low = mid;
for(int i = 1; i <= top; i ++) {
int v = st[i], nd = curd[v];
fill(g + 1, g + nd + 1, - INF);
dfs(v, fw[v] >= low ? 1 : -1);
for(int j = L; j <= nd && j <= R; j ++)
if(g[j] >= 0) return nowu = u, nowv = gu[j], 1;
if(i == 1) {
copy(g + 1, g + nd + 1, f + 1);
copy(gu + 1, gu + nd + 1, fu + 1);
} else {
static int q[N];
int ql = 0, qr = 0, pos = min(R - 1, ld); //!
for(int j = 1; j <= nd; j ++) {
for(; pos >= L - j && pos >= 1; pos --) {
for(; ql < qr && f[q[qr - 1]] <= f[pos]; qr --) ;
q[qr ++] = pos;
}
for(; ql < qr && q[ql] > R - j; ql ++) ;
if(ql < qr && f[q[ql]] + g[j] >= 0)
return nowu = fu[q[ql]], nowv = gu[j], 1;
}
for(int j = 1; j <= ld; j ++) if(f[j] < g[j]) f[j] = g[j], fu[j] = gu[j];
for(int j = ld + 1; j <= nd; j ++) f[j] = g[j], fu[j] = gu[j];
}
ld = nd;
}
return 0;
}
void solve(int u) {
int tsz = size; vis[u] = 1;
int l = 1, r = m, uu = -1, vv = -1, res = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(calc(u, tw[mid])) {
l = (res = mid) + 1;
uu = nowu; vv = nowv;
} else r = mid - 1;
}
if(res > ans) {
ans = res; ansu = uu; ansv = vv;
}
for(const Edge &e : G[u]) {
if(!vis[e.v]) {
rt = 0; size = sz[e.v] > sz[u] ? tsz - sz[u] : sz[e.v];
findrt(e.v); solve(rt);
}
}
}
int main() {
scanf("%d%d%d", &n, &L, &R);
for(int u, v, w, i = 1; i < n; i ++) {
scanf("%d%d%d", &u, &v, &w);
G[u].push_back({v, w});
G[v].push_back({u, w});
tw[i] = w;
}
sort(tw + 1, tw + n);
m = unique(tw + 1, tw + n) - tw - 1;
rt = 0; size = n; findrt(1); solve(rt);
printf("%d %d\n", ansu, ansv);
return 0;
}
「CF150E」Freezing with Style「点分治」「单调队列」的更多相关文章
- [P2216] [HAOI2007]理想的正方形 「单调队列」
思路:用单调队列分别维护行与列. 具体实现方法:是先用单调队列对每一行的值维护,并将a[][]每个区间的最大值,最小值分别存在X[][]和x[][]中. 那么X[][]与x[][]所存储的分别是1×n ...
- [POJ2823] Sliding Window 「单调队列」
我们从最简单的问题开始: 给定一个长度为N的整数数列a(i),i=0,1,...,N-1和窗长度k. 要求: f(i) = max{ a(i-k+1),a(i-k+2),..., a(i) },i ...
- 「CF986F」 Oppa Funcan Style Remastered
「CF986F」 Oppa Funcan Style Remastered Link 首先发现分解成若干个 \(k\) 的因数很蠢,事实上每个因数都是由某个质因子的若干倍组成的,所以可以将问题转换为分 ...
- loj#2483. 「CEOI2017」Building Bridges 斜率优化 cdq分治
loj#2483. 「CEOI2017」Building Bridges 链接 https://loj.ac/problem/2483 思路 \[f[i]=f[j]+(h[i]-h[j])^2+(su ...
- docker并不能把部署的工作「减少为0」,比较好的情况下是「基本减少为1」
很多人说docker改变了运维世界,这句话是从群体角度来说的,是统计学意义上的改变,像mysql,python这样被大规模使用的基础应用,docker化之后为整个群体所节省的时间是非常巨大的. 有人可 ...
- 「单调队列优化DP」P2034 选择数字
「单调队列优化DP」P2034 选择数字 题面描述: 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入格 ...
- CodeForces 150E: Freezing with Style
题目传送门:CF150E. 据说这个傻逼题还有一个 \(\log\) 的做法,但是我还不会. 题意简述: 给定一棵 \(n\)(\(2\le n\le 10^5\))个点的树,边有边权. 定义一条路径 ...
- 「GM_脚本」获取 GitHub 项目文件的 jsDelivr CDN 地址「好像没啥用系列」
基本信息: name:「 GitHub 」获取文件的 jsDelivr 地址 desc:获取项目文件的 CDN 地址 url: https://github.com/wdssmq/userscript ...
- loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)
题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se secon ...
随机推荐
- mysql全面整理(用于复习、查阅)--正在更新
Mysql学习 1. 关键字与函数名称全部大写 2. 数据库名称.表名称.字段名称全部小写 3. SQL语句必须以分号结尾 一.数据库基本操作 1. 创建.查看数据库 CREATE {DATABASE ...
- 更新到PS CC 2019 缩放的时候 按住shift变成不规则缩放了 反而不按住shift是等比例缩放
更新到PS CC 2019 缩放的时候 按住shift变成不规则缩放了 反而不按住shift是等比例缩放 更新到PS CC 2019 缩放的时候 按住shift变成不规则缩放了 反而不按住shift是 ...
- 稀疏检出-使用git检索出仓库里的某一个目录文件,而不是整个仓库的所有文件
具体工作意义是从某一个Git仓库 克隆时,只克隆检测出这个仓库里的某些文件夹内容,而不是跟平常那样把整个仓库的内容都克隆下来 从1.7.0版本开始git提供稀疏检出的功能.所谓稀疏检出就是本地版本库检 ...
- Python之原始数据-1
一.数据对于模型来说是基础,是数据成就了模型,而现在的又是一个数据时代,比如:淘宝等.通过对用户数据的分析挖掘,预测用户的消费习惯等,再比如:人工智能.通过提取摄像头的图片帧数,通过分析图片,得出具体 ...
- Hadoop HA 搭建
Hadoop HA 什么是 HA HA是High Available缩写,是双机集群系统简称,指高可用性集群,是保证业务连续性的有效解决方案,一般有两个或两个以上的节点,且分为活动节点及备用节点.通常 ...
- 我对xss以及sql的理解
我对xss以及sql的理解 本文作者:情殇(查看作者所有博文) 作者邮箱:3135117931@qq.com 发布时间: Fri, 12 Jul 2019 19:16:00 +0800 Xss和sql ...
- K2 BPM_康熙别烦恼(下篇)——审批矩阵_工作流引擎
康熙别烦恼(上篇)——分级授权 End 公司介绍:上海斯歌信息技术有限公司,聚焦企业所关注的管理挑战和压力,提供BPM平台及相关解决方案为主.2005年正式进入大中华地区,总部设在上海,并在北京.深圳 ...
- java线程中如何使用spring依赖注入
实现一个线程继承了Thread或实现Runnable接口,想在run方法中使用spring依赖注入(操作数据库),此时报错为空指针,就是说没有注入进来. 实验了几种方式,分别说一下优缺点. 1:写了工 ...
- docker linux下配置加速器
[root@foundation83 ~]# cd /etc/docker/[root@foundation83 docker]# vim daemon.json{ "registry-mi ...
- nginx日志文件的配置
文章来源 运维公会: nginx日志文件的配置 1.日志介绍 nginx有两种日志,一种是访问日志,一种是错误日志. 访问日志中记录的是客户端对服务器的所有请求. 错误日志中记录的是在访问过程中,因为 ...