hdu 4123-Bob’s Race 2011福州赛

http://acm.hdu.edu.cn/showproblem.php?pid=4123

哥的心都碎了,现场赛不知道什么原因竟然连long long 都没注意。菜鸟就是菜鸟,明年继续努力吧。

题意:

n个点的树,每个点有一个人,每个人会跑到离自己初始点距离最远的点上,
这个距离为distance[i]。给你m个查询,对于每个查询Q,找一段连续编号的人,
比如[left,right],满足 max( distance[i] i∈[left,right] ) – min( distance[i] i∈[left,right] ) ≤ Q,
并且使得length=right-left+1要最大,求这个最大的length

 

题目看似有点难,其实分析清楚了一步步来还是比较简单的。

首先 要找   “每个人会跑到离自己初始点距离最远的点上”——dis[i]

这个用树形dp很简单可以解决,保存两个从儿子走能走的最长距离和第二长距离

在第二遍搜的时候如果你搜到得儿子是最长的距离的那个,很显然你要拉第二长距离的儿子过来。这个还是自己理解吧....

 

中间 rmq

 

后面是 单调队列,保证答案只会变大。

View Code
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<vector>
  4 using namespace std;
  5 #include<algorithm>
  6 #include<string>
  7 #define N 50010
  8 #define M 510
  9 #define inf 200000000 
 10 int w[N],edge,id[N],an[M];
 11 __int64 dp[N][2],dis[N];
 12 struct qq{
 13     int id;
 14     __int64 l;
 15 }q[M];
 16 bool cmp(const qq &a,const qq &b){
 17     return a.l<b.l;
 18 }
 19 struct node{
 20     int v,next;
 21     __int64 l;
 22 }e[N*2];
 23 void add(int u,int v,__int64 l){
 24     e[edge].v=v;
 25     e[edge].l=l;
 26     e[edge].next=w[u];
 27     w[u]=edge++;
 28 }
 29 void dfs1(int u,int no){
 30     for(int i=w[u];i!=-1;i=e[i].next){
 31         int v=e[i].v;
 32         if(v!=no){
 33             dfs1(v,u);
 34             if(dp[v][0]+e[i].l>dp[u][0]){
 35                 dp[u][1]=dp[u][0];
 36                 id[u]=v,dp[u][0]=dp[v][0]+e[i].l;
 37             }
 38             else if(dp[v][0]+e[i].l>dp[u][1]) dp[u][1]=dp[v][0]+e[i].l;
 39         }
 40     }
 41 }
 42 
 43 
 44 void dfs2(int u,int no,__int64 l){
 45     dis[u]=max(l,dp[u][0]);
 46     for(int i=w[u];i!=-1;i=e[i].next){
 47         int v=e[i].v;
 48         if(v!=no){
 49             if(v==id[u]) dfs2(v,u,max(l,dp[u][1])+e[i].l);
 50             else dfs2(v,u,dis[u]+e[i].l);
 51         }
 52     }
 53 }
 54 
 55 int dp_max[N][20],dp_min[N][20];
 56 __int64 p[20];
 57 int max_id(int x,int y){
 58     return dis[x]>dis[y]?x:y;
 59 }
 60 int min_id(int x,int y){
 61     return dis[x]>dis[y]?y:x;
 62 }
 63 int log(int x){
 64     int i=0;
 65     while(p[i]<=x) i++; 
 66     return i-1;
 67 }
 68 int get_max_id(int x,int y){
 69     int t=log(y-x+1);
 70     return max_id(dp_max[x][t],dp_max[y-p[t]+1][t]);
 71 }
 72 int get_min_id(int x,int y){
 73     int t=log(y-x+1);
 74     return min_id(dp_min[x][t],dp_min[y-p[t]+1][t]);
 75 }
 76 
 77 __int64 get_min(int x,int y){
 78     return dis[get_min_id(x,y)];
 79 }
 80 __int64 get_max(int x,int y){
 81     return dis[get_max_id(x,y)];
 82 }
 83 void RMQ(int n){
 84     int i,j,l=n,t=0;
 85     p[0]=1;
 86     for(i=1;i<18;i++) 
 87         p[i]=p[i-1]<<1;
 88     t=log(n);
 89     for(i=1;i<=n;i++) 
 90         dp_max[i][0]=dp_min[i][0]=i;
 91     for(i=1;i<=t;i++){
 92         l=n-p[i]+1;
 93         for(j=1;j<=l;j++){
 94             dp_max[j][i]=max_id(dp_max[j][i-1],dp_max[j+p[i-1]][i-1]);
 95             dp_min[j][i]=min_id(dp_min[j][i-1],dp_min[j+p[i-1]][i-1]);
 96         }
 97     }
 98 }
 99 
100 int main(){
101 //#ifndef ONLINE_JUDGE
102 //    freopen("C:\\Users\\Slon\\Desktop\\in.txt","r",stdin);
103 //    freopen("C:\\Users\\Slon\\Desktop\\out.txt","w",stdout);
104 //#endif
105     int n,m,a,b;
106     __int64 c;
107     while(scanf("%d%d",&n,&m)){
108         if(!n&&!m) break;
109         edge=0;
110         memset(w,-1,sizeof(int)*(n+1));
111         for(int i=1;i<n;++i){
112             scanf("%d%d%I64d",&a,&b,&c);
113             add(a,b,c);
114             add(b,a,c);
115         }
116         memset(dis,0,sizeof(__int64)*(n+1));
117         memset(dp,0,sizeof(dp));
118         dfs1(1,1);
119         dfs2(1,1,0);
120 
121         RMQ(n);
122 
123         for(int i=0;i<m;++i){
124             scanf("%I64d",&q[i].l);
125             q[i].id=i;
126         }
127         sort(q,q+m,cmp);
128         
129         for(int i=0;i<m;++i){
130             int ans,start=1;
131             if(!i) ans=1;
132             else ans=an[q[i-1].id];
133             while(1){
134                 int j=start+ans-1;
135                 for(;j<=n&&get_max(start,j)-get_min(start,j)<=q[i].l;++j);
136                 if(ans<j-start) ans=j-start;
137                 if(j==n+1) break;
138                 ++start;
139             }
140             an[q[i].id]=ans;
141         }
142         for(int i=0;i<m;++i) printf("%d\n",an[i]);
143     }
144     return 0;
145 }

转载于:https://www.cnblogs.com/slon/archive/2012/02/20/2360454.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值