HDU 4123(树上任意点到其他点的最远距离,rmq

题目:求出一棵树上任意一点能到的最远距离,然后若干询问,问区间内最大最小距离只差小于q的区间最长有多长。

思路:最远距离通过两次dfs树形dp求得,询问需要先用st表处理一下,然后线性扫。基本是参考kuangbin的。

ps:可能是我写挫了。。用vector做邻接表是1996ms过了一次,然后就是无限tle。。。。不得不改成手写链表才搞到1500ms。。。vector感觉不能随便用了啊。。。。。。

http://www.cnblogs.com/kuangbin/archive/2013/11/08/3414812.html

#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <set>
#include <cmath>
#define pb push_back
#define fs first
#define se second
#define sq(x) (x)*(x)
#define eps 0.0000000001
#define IINF (1<<30)
#define clr(x) memset((x),0,sizeof (x))
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
const int maxv=5e4+300;
int N,M;
struct EDGE{
    int t,d;
    EDGE *nt;
}pool[maxv*3];
int ph=0;
EDGE *newedge(){
    pool[ph].nt=NULL;
    return &pool[ph++];
}
EDGE *head[maxv],*tail[maxv];
int maxd[maxv],maxdn[maxv],smaxd[maxv],smaxdn[maxv];
void addedge(int x,int y,int z){
    tail[x]->nt=newedge();
    tail[x]=tail[x]->nt;
    tail[x]->t=y,tail[x]->d=z;
}
void dfs1(int v,int fa){
    for(EDGE *i=head[v]->nt;i!=NULL;i=i->nt){
        int u=i->t;
        int len=i->d;
        if(u==fa) continue;
        dfs1(u,v);
        if(maxd[u]+len>smaxd[v]){
            smaxd[v]=maxd[u]+len;
            smaxdn[v]=u;
            if(smaxd[v]>maxd[v]){
                swap(smaxd[v],maxd[v]);
                swap(smaxdn[v],maxdn[v]);
            }
        }
    }
}
void dfs2(int v,int fa){
    for(EDGE *i=head[v]->nt;i!=NULL;i=i->nt){
        int u=i->t;
        int len=i->d;
        if(u==fa) continue;
        if(u==maxdn[v]){
            if(smaxd[v]+len>smaxd[u]){
                smaxd[u]=smaxd[v]+len;
                smaxdn[u]=v;
                if(smaxd[u]>maxd[u]){
                    swap(smaxd[u],maxd[u]);
                    swap(smaxdn[u],maxdn[u]);
                }
            }
        }else{
            if(maxd[v]+len>smaxd[u]){
                smaxd[u]=maxd[v]+len;
                smaxdn[u]=v;
                if(smaxd[u]>maxd[u]){
                    swap(smaxd[u],maxd[u]);
                    swap(smaxdn[u],maxdn[u]);
                }
            }
        }
        dfs2(u,v);
    }
}
ll STmin[maxv][30];
ll STmax[maxv][30];
void makeST(){
    memset(STmin,0x3f,sizeof STmin);
    memset(STmax,0,sizeof STmax);
    for(int i=1;i<=N;i++){
        STmin[i][0]=STmax[i][0]=maxd[i];
    }
    for(int k=1;k<25;k++){
        for(int i=1;i+(1<<k)<=N+1;i++){
            STmin[i][k]=min(STmin[i][k-1],STmin[i+(1<<(k-1))][k-1]);
            STmax[i][k]=max(STmax[i][k-1],STmax[i+(1<<(k-1))][k-1]);
        }
    }
}
int getdif(int l,int r){
    int k=0;
    while((1<<(k+1))<r-l) k++;
    return max(STmax[l][k],STmax[r-(1<<k)][k])-min(STmin[l][k],STmin[r-(1<<k)][k]);
}
void work(){
    clr(maxd);clr(maxdn);clr(smaxd);clr(smaxdn);
    dfs1(1,0);
    dfs2(1,0);
    makeST();
    while(M--){
        int Q;
        scanf("%d",&Q);
        int ans=0;
        int j=1;
        for(int i=1;i<=N;i++){
            while(j<=N&&getdif(i,j+1)<=Q){
                j++;
            }
            ans=max(ans,j-i);
        }
        printf("%d\n",ans);
    }

}
void init(){
    ph=0;
    for(int i=0;i<=N;i++){
        head[i]=newedge();
        head[i]->nt=NULL;
        tail[i]=head[i];
    }
}
int main(){
    freopen("/home/files/CppFiles/in","r",stdin);
    /*    std::ios::sync_with_stdio(false);
        std::cin.tie(0);*/
    while(cin>>N>>M){
        if(N==0&&M==0) break;
        init();
        for(int i=0;i<N-1;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z);
            addedge(y,x,z);
        }
        work();
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Cw-trip/p/4700852.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值