给定一棵n个点并且有边权的树,每个点的权值为该点能走的最远长度,并输入m个询问,每次询问最多有多少个编号连续的点,他们的最大最小点权差小于等于Q。N<=50000 M<=500 Q<=10000000

  我们知道一个点能走的最远端点一定是树的直径的端点,所以我们只需从树的直径两端点dfs,就可以求出每个点能到的最远长度。。然后rmq+尺取即可。

这道题如果用系统的log会tle,所以必须手打log2。原理会再放一篇博客。

 #include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn=, maxmi=, INF=1e9;
//const double exp=1e-6;
int n, m, cntedge, maxdist, maxdistpos;
int fir[maxn], val[maxn];
int fmaxm[maxn][maxmi], fminm[maxn][maxmi];
struct Edge{
int to, v, next;
};
Edge edge[maxn]; void addedge(int x, int y, int z){
++cntedge;
Edge &nowedge1=edge[cntedge];
nowedge1.to=y, nowedge1.v=z, nowedge1.next=fir[x];
fir[x]=cntedge;
++cntedge;
Edge &nowedge2=edge[cntedge];
nowedge2.to=x, nowedge2.v=z, nowedge2.next=fir[y];
fir[y]=cntedge;
return;
} void dfs(int now, int par, int dist){
int nowedge, nowson;
nowedge=fir[now];
while (nowedge){
nowson=edge[nowedge].to;
if (nowson==par){
nowedge=edge[nowedge].next;
continue;
}
dfs(nowson, now, dist+edge[nowedge].v);
nowedge=edge[nowedge].next;
}
if (dist>val[now]) val[now]=dist;
if (dist>maxdist){
maxdist=dist;
maxdistpos=now;
}
return;
} int flog2(float x) {
return ((unsigned&)x>>&)-;
}
int dvalue(int head, int tail){
int maxm=, minm=1e9;
int lognum=flog2(tail-head+);
maxm=max(fmaxm[head][lognum], fmaxm[tail-(<<lognum)+][lognum]);
minm=min(fminm[head][lognum], fminm[tail-(<<lognum)+][lognum]);
return maxm-minm;
} void init(){
memset(fir, , sizeof(fir));
memset(val, , sizeof(val));
for (int i=; i<maxn; ++i){
edge[i].next=edge[i].to=edge[i].v=;
}
cntedge=;
} int ri(){
char c;
int flag=, r=;
do{
c=getchar();
if (c=='-') flag=-;
} while (!isgraph(c));
do{
r=r*+c-;
c=getchar();
} while (isgraph(c));
return r*flag;
} int main(){
int x, y, z;
while (~scanf("%d%d", &n, &m)){
if (n==&&m==) break;
init();
for (int i=; i<n; ++i){
x=ri(), y=ri(), z=ri();
addedge(x, y, z);
}
int s=, far1, far2;
maxdist=, dfs(s, , );
far1=maxdistpos;
maxdist=, dfs(far1, , );
far2=maxdistpos;
maxdist=, dfs(far2, , );
//for (int i=1; i<=n; ++i)
//printf("%d\n", val[i]);
int q=;
for (int i=; i<=n; ++i)
fmaxm[i][]=fminm[i][]=val[i];
for (int i=; i<maxmi; ++i){
for (int j=; j<=n-(<<i)+; ++j){
fmaxm[j][i]=max(fmaxm[j][i-], fmaxm[j+(<<(i-))][i-]);
fminm[j][i]=min(fminm[j][i-], fminm[j+(<<(i-))][i-]);
}
}
int h=, t=, maxm=;
for (int i=; i<m; ++i){
q=ri();
h=, t=, maxm=;
while (t<=n){
if (dvalue(h, t)<=q) ++t;
else ++h;
if ((t-h)>maxm) maxm=t-h;
}
printf("%d\n", maxm);
}
}
return ;
}

树的直径+rmq+(伪)单调队列 -HDU4123的更多相关文章

  1. 【bzoj1999】[Noip2007]Core树网的核 树的直径+双指针法+单调队列

    题目描述 给出一棵树,定义一个点到一条路径的距离为这个点到这条路径上所有点的距离的最小值.求一条长度不超过s的路径,使得所有点到这条路径的距离的最大值最小. 输入 包含n行: 第1行,两个正整数n和s ...

  2. hdu 4123 Bob’s Race 树的直径+rmq+尺取

    Bob’s Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Probl ...

  3. 51Nod.1766.树上最远点对(树的直径 RMQ 线段树/ST表)

    题目链接 \(Description\) 给定一棵树.每次询问给定\(a\sim b,c\sim d\)两个下标区间,从这两个区间中各取一个点,使得这两个点距离最远.输出最远距离. \(n,q\leq ...

  4. HDU - 5289 Assignment (RMQ+二分)(单调队列)

    题目链接: Assignment  题意: 给出一个数列,问其中存在多少连续子序列,使得子序列的最大值-最小值<k. 题解: RMQ先处理出每个区间的最大值和最小值(复杂度为:n×logn),相 ...

  5. 求最长的任意两元素差不超过M的子段——双指针+单调队列hdu4123

    换根dp的部分比较容易,难点在于求求最长的任意两元素差不超过M的子段 首先会想到双指针维护(尺取法),如果p1,p2间的max-min>M,那么p1向右移动,直到p1,p2间的max-min&g ...

  6. 洛谷 P2216 [HAOI2007]理想的正方形 || 二维RMQ的单调队列

    题目 这个题的算法核心就是求出以i,j为左上角,边长为n的矩阵中最小值和最大值.最小和最大值的求法类似. 单调队列做法: 以最小值为例: q1[i][j]表示第i行上,从j列开始的n列的最小值.$q1 ...

  7. HDU 4123 Bob’s Race 树的直径 RMQ

    Bob’s Race Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=41 ...

  8. 【HDU6701】Make Rounddog Happy【权值线段树+双向单调队列】

    题意:给你一个序列,求满足要求的子序列个数,其中要求为: 1.子序列的max-子序列长度len<=k 2.子序列中不出现重复的数字 题解:首先看到子序列max,很容易想到枚举最大值然后分治,这个 ...

  9. cf1208 E Let Them Slide(差分+RMQ\单调队列)

    题意 如题目的图所示,每行都可以左右移动,但是数字不允许断开,且不许越界(宽度为w). 单独求每一列的最大的和为多少. 思路 对于每一列来说,在每一行上都有一个可以取到的区间, 所以,对于一列来说,答 ...

随机推荐

  1. 分享知识-快乐自己:Struts2 拦截器 与 过滤器

    拦截器的使用以及配置: package com.gdbd.interceptor; import com.gdbd.pojo.UserInfo; import com.opensymphony.xwo ...

  2. java后端书单

    Java开发工程师一般负责后端开发,当然也有专门做Java Web的工程师,但是随着前后端的分离,越来越多的Java工程师需要往大后端方向发展. 今天我们就来介绍一下Java后端开发者的书单. 首先要 ...

  3. python习题-产生8位随机密码要包含大小写及数字

    # 1.写一个产生密码的程序,# 输入次数,输入多少次就产生多少条数据,# 要求密码必须包含大写字母.小写字母和数字,长度8位,不能重复 #需求分析#1.循环,输入什么就循环多少次#2.随机来取值,是 ...

  4. 【二叉查找树】02不同的二叉查找树个数II【Unique Binary Search Trees II】

    提到二叉查找树,就得想到二叉查找树的递归定义, 左子树的节点值都小于根节点,右子树的节点值都大于根节点. +++++++++++++++++++++++++++++++++++++++++++++++ ...

  5. C语言小程序(三)、判断两个日期之差

    输入两个日期,计算之间相差多少天. 用了两种方法实现,第二种利用结构体,代码比较清晰,其余的都一样. 1.普通的写法 #include <stdio.h> int leapyear(int ...

  6. bzoj 2342: 双倍回文 回文自动机

    题目大意: 定义双倍回文串的左一半和右一半均是回文串的长度为4的倍数的回文串 求一个给定字符串中最长的双倍回文串的长度 题解: 我们知道可以简单地判定以某一点结尾的最长回文串 我们知道可以简单地判定以 ...

  7. BZOJ3307:雨天的尾巴

    浅谈线段树合并:https://www.cnblogs.com/AKMer/p/10251001.html 题目传送门:https://lydsy.com/JudgeOnline/problem.ph ...

  8. bzoj 2096 [POI2004]ZAW——二进制枚举

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2069 可以把直接相连的点分成  从1点出的一部分  和  走向1点的一部分.多起点最短路就和 ...

  9. Poj 1458 Common Subsequence(LCS)

    一.Description A subsequence of a given sequence is the given sequence with some elements (possible n ...

  10. unittest 执行测试脚本输出测试报告

    import unittestimport HTMLTestRunnertest as HTMLTestRunner#获取路径path = './'#创建测试套件,读取测试脚本suite = unit ...