HDU 4123(RMQ(o1)模板 , 树直径)

题目的意思:

给出N(n<=50000)个点的一棵树,有M(M<=500)个查询,每个查询限定一个值Q, 求最大连续节点编号的长度,使得从这些点走到的最远距离的最大差不超过Q


先求出每个点的最远到达距离,树直径简单求解方法。

RMQ处理得到的最远距离数组,线性扫描求每个值

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef long long ll;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define rep(i ,n) for(int i =0 ; i<n; i++)
#define rep1(i ,x , y ) for(int i=x;i<=y;i++)
const int N=200105;
int c[N];
int max_[N][20],min_[N][20],lg2[N]; //20不一定是唯一的。需要计算log(N)/log(2)
void ST(int *a,int n)
{
    lg2[0]=-1;
    for(int i=1;i<=n;i++)
        lg2[i]=lg2[i-1]+(i&(i-1)?0:1);
    for(int i=0;i<n;i++) max_[i][0]=a[i];  //a第一个数从零开始
    for(int j=1;j<=lg2[n];j++)
        for(int i=0;lg2[n-i]>=j;i++)
            max_[i][j]=max(max_[i][j-1],max_[i+(1<<(j-1))][j-1]);
    for(int i=0;i<n;i++) min_[i][0]=a[i];  //a第一个数从零开始
    for(int j=1;j<=lg2[n];j++)
        for(int i=0;lg2[n-i]>=j;i++)
            min_[i][j]=min(min_[i][j-1],min_[i+(1<<(j-1))][j-1]);
}
int RMQ_Max(int x,int y)
{
    int k=lg2[y-x+1];
    return max(max_[x][k],max_[y-(1<<k)+1][k]);
}
int RMQ_Min(int x,int y)
{
    int k=lg2[y-x+1];
    return min(min_[x][k],min_[y-(1<<k)+1][k]);
}
typedef pair<int,int> pii;
vector<pii> G[N];
int dis[2][N], FA , fir , sec;
void dfs(int* d , int u, int fa,  int dep){
    d[u] = dep;
    rep(i , G[u].size()){
        if(G[u][i].first != fa){
              dfs(d , G[u][i].first, u , dep + G[u][i].second);
        }
    }
    if(d[u] > d[FA]) FA = u;
}
int n,m;
int main()
{
   while(scanf("%d %d",&n,&m)==2 && n){
        rep1(i , 1 , n) G[i].clear();
        rep(i , n - 1){
            int u ,v , w;
            scanf("%d %d %d",&u,&v,&w);
            G[u].push_back(pii(v , w));
            G[v].push_back(pii(u , w));
        }
        FA = 1;
        dfs(dis[0] , 1 , -1 , 0);
        fir = FA;
        dfs(dis[0] , FA , -1 , 0);
        sec = FA;
        dfs(dis[1] , FA , -1 , 0);
        rep1(i , 1 , n){
            c[i - 1] = max(dis[1][i] , dis[0][i]);
        }
        ST(c , n);
        while(m--){
            int lim ; scanf("%d",&lim);
            int l = 0 , max_ = 0;
            for(int r = 0 ; r<n ; r++){
                 while(l < r){
                     if(RMQ_Max(l , r) - RMQ_Min(l , r) <= lim) break;
                     l++;
                 }
                 max_ = max(max_ , r - l + 1);
            }
            printf("%d\n",max_);
        }
   }
   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值