CodeForces 150E: Freezing with Style
题目传送门:CF150E。
据说这个傻逼题还有一个 \(\log\) 的做法,但是我还不会。
题意简述:
给定一棵 \(n\)(\(2\le n\le 10^5\))个点的树,边有边权。
定义一条路径的权值为路径经过的边的边权的中位数,若经过偶数条边则取两个中位数中较大的那个。
求长度介于 \(l\) 到 \(r\)(\(1\le l\le r<n\))之间的路径的最大权值,并输出这个路径的两端点。
题解:
看到中位数的定义,首先想到二分答案,假设二分的值为 \(\mathrm{mid}\),将边权 \(\ge\mathrm{mid}\) 的边看作 \(+1\),将边权 \(<\mathrm{mid}\) 的边看作 \(-1\),则一条路径的权值大于等于 \(\mathrm{mid}\) 当且仅当其经过的边的和大于等于 \(0\)。
二分了一个值后,考虑使用点分治统计路径。
合并子树时相当于查询一个滑动窗口内的最大值,用单调队列维护即可。
对当前分治块内统计时要注意需要先处理较小的子树以保证复杂度。
下面是代码,时间复杂度 \(\mathcal{O}(n\log^2 n)\)。
#include <cstdio>
#include <vector>
#include <algorithm>
const int Inf = 0x3f3f3f3f;
const int MN = 100005;
int N, L, R, Ans = -1, AnsU, AnsV;
int uv[MN], w[MN];
std::vector<int> G[MN];
int dw[MN], M;
int vis[MN], siz[MN], tsiz, rsiz, Root;
void GetRoot(int u, int fz) {
siz[u] = 1;
int nsiz = 0;
for (auto i : G[u]) {
int v = uv[i] ^ u;
if (v == fz || vis[v]) continue;
GetRoot(v, u), siz[u] += siz[v];
if (nsiz < siz[v]) nsiz = siz[v];
}
if (nsiz < tsiz - siz[u]) nsiz = tsiz - siz[u];
if (rsiz > nsiz) rsiz = nsiz, Root = u;
}
int stk[MN], tp, _U;
inline bool cmp(int i, int j) {
return siz[uv[i] ^ _U] < siz[uv[j] ^ _U];
}
int seq[MN], sequ[MN], odep, tmp[MN], tmpu[MN], ndep;
void DFS(int u, int fz, int d, int x, int y) {
if (tmp[d] < x) tmp[d] = x, tmpu[d] = u;
if (ndep < d) ndep = d;
for (auto i : G[u]) {
int v = uv[i] ^ u;
if (v == fz || vis[v]) continue;
DFS(v, u, d + 1, x + (w[i] >= y ? 1 : -1), y);
}
}
int ucal, vcal;
bool Calc(int u, int x) {
static int que[MN];
seq[odep = 0] = 0, sequ[0] = u;
for (int i = 1; i <= tp; ++i) {
int v = uv[stk[i]] ^ u;
for (int j = 1; j <= siz[v]; ++j) tmp[j] = -Inf;
ndep = 0, DFS(v, u, 1, w[stk[i]] >= x ? 1 : -1, x);
int l = 1, r = 0, lb = odep, rb = odep + 1;
for (int j = 1; j <= ndep; ++j) {
while (rb > 0 && rb > L - j) {
--rb;
while (l <= r && seq[que[r]] < seq[rb]) --r;
que[++r] = rb;
}
while (lb >= 0 && lb > R - j) {
--lb;
while (l <= r && que[l] > lb) ++l;
}
if (l <= r && seq[que[l]] + tmp[j] >= 0) {
ucal = sequ[que[l]], vcal = tmpu[j];
return 1;
}
}
while (odep < ndep) seq[++odep] = -Inf;
for (int j = 1; j <= ndep; ++j)
if (seq[j] < tmp[j])
seq[j] = tmp[j], sequ[j] = tmpu[j];
}
return 0;
}
void Solve(int u) {
int nsiz = tsiz;
tp = 0;
for (auto i : G[u]) {
int v = uv[i] ^ u;
if (vis[v]) continue;
siz[v] = siz[v] > siz[u] ? nsiz - siz[u] : siz[v];
stk[++tp] = i;
}
_U = u, std::sort(stk + 1, stk + tp + 1, cmp);
int lb = 1, rb = M, mid, ans = 0, ansu = 0, ansv = 0;
while (lb <= rb) {
mid = (lb + rb) >> 1;
if (Calc(u, dw[mid])) {
ans = mid;
ansu = ucal, ansv = vcal;
lb = mid + 1;
}
else rb = mid - 1;
}
if (Ans < dw[ans]) {
Ans = dw[ans];
AnsU = ansu, AnsV = ansv;
}
vis[u] = 1;
for (auto i : G[u]) {
int v = uv[i] ^ u;
if (vis[v]) continue;
rsiz = tsiz = siz[v], GetRoot(v, 0), Solve(Root);
}
}
int main() {
scanf("%d%d%d", &N, &L, &R);
for (int i = 1; i < N; ++i) {
int x, y;
scanf("%d%d%d", &x, &y, &w[i]);
uv[i] = x ^ y;
G[x].push_back(i);
G[y].push_back(i);
dw[i] = w[i];
}
std::sort(dw + 1, dw + N);
M = std::unique(dw + 1, dw + N) - dw - 1;
rsiz = tsiz = N, GetRoot(1, 0), Solve(Root);
printf("%d %d\n", AnsU, AnsV);
return 0;
}
CodeForces 150E: Freezing with Style的更多相关文章
- CF 150E Freezing with Style [长链剖分,线段树]
\(sol:\) 给一种大常数 \(n \log^2 n\) 的做法 考虑二分,由于是中位数,我们就二分这个中位数,\(x>=mid\)则设为 \(1\),否则为 \(-1\) 所以我们只需要找 ...
- [Codeforces 485F] Oppa Funcan Style Remastered
[题目链接] https://codeforces.com/contest/986/problem/F [算法] 不难发现 , 每个人都在且仅在一个简单环中 , 设这些环长的长度分别为 A1, A2 ...
- Codeforces 986F - Oppa Funcan Style Remastered(同余最短路)
Codeforces 题面传送门 & 洛谷题面传送门 感谢此题教会我一个东西叫做同余最短路(大雾 首先这个不同 \(k\) 的个数 \(\le 50\) 这个条件显然是让我们对每个 \(k\) ...
- 「CF150E」Freezing with Style「点分治」「单调队列」
题意 给定一颗带边权的树,求一条边数在\(L\).\(R\)之间的路径,并使得路径上边权的中位数最大.输出一条可行路径的两个端点.这里若有偶数个数,中位数为中间靠右的那个. \(n, L, R\leq ...
- CodeForces - 344B Simple Molecules (模拟题)
CodeForces - 344B id=46665" style="color:blue; text-decoration:none">Simple Molecu ...
- CodeForces - 344D Alternating Current (模拟题)
id=46667" style="color:blue; text-decoration:none">CodeForces - 344D id=46667" ...
- CodeForces - 344A Magnets (模拟题)
CodeForces - 344A id=46664" style="color:blue; text-decoration:none">Magnets Time ...
- python爬虫学习(5) —— 扒一下codeforces题面
上一次我们拿学校的URP做了个小小的demo.... 其实我们还可以把每个学生的证件照爬下来做成一个证件照校花校草评比 另外也可以写一个物理实验自动选课... 但是出于多种原因,,还是绕开这些敏感话题 ...
- Codeforces Round #313 (Div. 2)B.B. Gerald is into Art
B. Gerald is into Art Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/ ...
随机推荐
- Linux性能优化实战学习笔记:第五十三讲
一.上节回顾 在前面的内容中,我为你介绍了很多性能分析的原理.思路以及相关的工具.不过,在实际的性能分析中,一个很常见的现象是,明明发生了性能瓶颈,但当你登录到服务器中想要排查的时候,却发现瓶颈已经消 ...
- JVM系列之三:类装载器子系统
0. JVM架构图 Java虚拟机主要分为五大模块:类装载器子系统.运行时数据区.执行引擎.本地方法接口和垃圾收集模块. 1. 类的加载 虚拟机类装载器子系统:虚拟机把描述类的数据从class文件加载 ...
- 第30课 线程同步(std::condition_variable)
一. 条件变量 (一)条件变量概述 多线程访问一个共享资源(或称临界区),不仅需要用互斥锁实现独享访问避免并发错误,在获得互斥锁进入临界区后,还需检查特定条件是否成立.当某个线程修改测试条件后,将通知 ...
- 大话设计模式Python实现-简单工厂模式
简单工厂模式(Simple Factory Pattern):是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类. 下面使用简单工厂模式实现一个简单的四则运算 #!/usr/ ...
- wifi串口服务器
下面与大家分享上海卓岚无线wifi串口服务器ZLAN7104创建虚拟串口的设置使用心得 一.7104网线连接计算机,用ZLVircom即可搜索并配置 其中,串口设置需要匹配实际所接的串口设备,配置为相 ...
- Docker 部署ELK
1.安装docker前安装pip sudo yum -y install epel-release sudo yum install python-pip 2.安装docker #安装依赖包 yum ...
- Entity Framework 学习系列(5) - EF 相关查询
目录 写在前面 一.使用Stopwatch 查询执行效率 二.简单查询 1.Linq写法: 2.Lambda表达式写法: 三.条件查询 1.Linq 写法 2.lambda 写法 四.聚合函数 1.L ...
- vue中操作localstorage
首先在子组件将localstorage方法进行封装 在父组件中对其进行引用 将输入的值存入到定义的searchHistory数组中,存储localstorage需要传两个参数,变量名为searchHi ...
- Javascript屏蔽Backspace回退页面
允许对输入框密码框等控件删除字符,但是不允许页面进行回退 <html lang="en" xmlns="http://www.w3.org/1999/xhtml&q ...
- webapi 返回类型
参考 大神;https://www.cnblogs.com/landeanfen/p/5501487.html