[HDU4123]Bob’s Race

题目大意:
给定一棵$n$个点并且有边权的树,每个点的权值为该点能走的最远长度,并输入$m$个询问,每次询问最多有多少个编号连续的点,他们的最大最小点权差小于等于$Q$。

思路:
两趟DP(DFS)求出每个点能走的最远长度,然后用ST算法预处理出每一段最大最小值。
对于每组询问,用尺取法求出最大值。
注意log2不能用cmath里面的函数(尤其是不能在for语句上),不然会TLE,最好是自己实现。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<vector>
 4 inline int getint() {
 5     char ch;
 6     while(!isdigit(ch=getchar()));
 7     int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 inline int log2(const float x){
12     return ((unsigned&)x>>23&255)-127;
13 }
14 const int N=50001,logN=16;
15 struct Edge {
16     int to,w;
17 };
18 std::vector<Edge> e[N];
19 inline void add_edge(const int u,const int v,const int w) {
20     e[u].push_back((Edge){v,w});
21 }
22 int w[N][3],son[N];
23 void dfs1(const int x,const int par) {
24     w[x][0]=w[x][1]=0;
25     for(unsigned i=0;i<e[x].size();i++) {
26         int &y=e[x][i].to;
27         if(y==par) continue;
28         dfs1(y,x);
29         if(w[y][0]+e[x][i].w>w[x][0]) {
30             w[x][1]=w[x][0];
31             w[x][0]=w[y][0]+e[x][i].w;
32             son[x]=y;
33         }
34         else if(w[y][0]+e[x][i].w>w[x][1]) {
35             w[x][1]=w[y][0]+e[x][i].w;
36         }
37     }
38 }
39 void dfs2(const int x,const int par) {
40     for(unsigned i=0;i<e[x].size();i++) {
41         int &y=e[x][i].to;
42         if(y==par) continue;
43         w[y][2]=std::max(w[x][2],son[x]!=y?w[x][0]:w[x][1])+e[x][i].w;
44         dfs2(y,x);
45     }
46 }
47 int max[N][logN],min[N][logN];
48 inline int getsum(const int l,const int r) {
49     int k=log2(r-l+1);
50     return std::max(max[l][k],max[r-(1<<k)+1][k])-std::min(min[l][k],min[r-(1<<k)+1][k]);
51 }
52 int main() {
53     for(;;) {
54         int n=getint(),m=getint();
55         if(!n&&!m) return 0;
56         for(int i=1;i<n;i++) {
57             int u=getint(),v=getint(),w=getint();
58             add_edge(u,v,w);
59             add_edge(v,u,w);
60         }
61         dfs1(1,0);
62         dfs2(1,0);
63         for(int i=1;i<=n;i++) {
64             max[i][0]=min[i][0]=std::max(w[i][0],w[i][2]);
65         }
66         for(int j=1;1<<j<=n;j++) {
67             for(int i=1;i<=n-(1<<j)+1;i++) {
68                 max[i][j]=std::max(max[i][j-1],max[i+(1<<(j-1))][j-1]);
69                 min[i][j]=std::min(min[i][j-1],min[i+(1<<(j-1))][j-1]);
70             }
71         }
72         while(m--) {
73             int q=getint(),ans=0;
74             for(int l=1,r=1;l<=r;l++) {
75                 for(;r<=n&&getsum(l,r)<=q;r++);
76                 ans=std::max(ans,r-l);
77             }
78             printf("%d\n",ans);
79         }
80         for(int i=1;i<=n;i++) e[i].clear();
81     }
82 }

 

转载于:https://www.cnblogs.com/skylee03/p/7429190.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值