树的直径+rmq+(伪)单调队列 -HDU4123

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

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

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

  1 #include <cctype>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <algorithm>
  6 using namespace std;
  7 
  8 const int maxn=50005, maxmi=18, INF=1e9;
  9 //const double exp=1e-6;
 10 int n, m, cntedge, maxdist, maxdistpos;
 11 int fir[maxn], val[maxn];
 12 int fmaxm[maxn][maxmi], fminm[maxn][maxmi];
 13 struct Edge{
 14     int to, v, next;
 15 };
 16 Edge edge[maxn];
 17 
 18 void addedge(int x, int y, int z){
 19     ++cntedge;
 20     Edge &nowedge1=edge[cntedge];
 21     nowedge1.to=y, nowedge1.v=z, nowedge1.next=fir[x];
 22     fir[x]=cntedge;
 23     ++cntedge;
 24     Edge &nowedge2=edge[cntedge];
 25     nowedge2.to=x, nowedge2.v=z, nowedge2.next=fir[y];
 26     fir[y]=cntedge;
 27     return;
 28 }
 29 
 30 void dfs(int now, int par, int dist){
 31     int nowedge, nowson;
 32     nowedge=fir[now];
 33     while (nowedge){
 34         nowson=edge[nowedge].to;
 35         if (nowson==par){
 36             nowedge=edge[nowedge].next;
 37             continue;
 38         }
 39         dfs(nowson, now, dist+edge[nowedge].v);
 40         nowedge=edge[nowedge].next;
 41     }
 42     if (dist>val[now]) val[now]=dist;
 43     if (dist>maxdist){
 44         maxdist=dist;
 45         maxdistpos=now;
 46     }
 47     return;
 48 }
 49 
 50 int flog2(float x) {
 51     return ((unsigned&)x>>23&255)-127;
 52 }
 53 int dvalue(int head, int tail){
 54     int maxm=0, minm=1e9;
 55     int lognum=flog2(tail-head+1);
 56     maxm=max(fmaxm[head][lognum], fmaxm[tail-(1<<lognum)+1][lognum]);
 57     minm=min(fminm[head][lognum], fminm[tail-(1<<lognum)+1][lognum]);
 58     return maxm-minm;
 59 }
 60 
 61 void init(){
 62     memset(fir, 0, sizeof(fir));
 63     memset(val, 0, sizeof(val));
 64     for (int i=0; i<maxn; ++i){
 65         edge[i].next=edge[i].to=edge[i].v=0;
 66     }
 67     cntedge=0;
 68 }
 69 
 70 int ri(){
 71     char c;
 72     int flag=1, r=0;
 73     do{
 74         c=getchar();
 75         if (c=='-') flag=-1;
 76     } while (!isgraph(c));
 77     do{
 78         r=r*10+c-48;
 79         c=getchar();
 80     } while (isgraph(c));
 81     return r*flag;
 82 }
 83 
 84 int main(){
 85     int x, y, z;
 86     while (~scanf("%d%d", &n, &m)){
 87         if (n==0&&m==0) break;
 88         init();
 89         for (int i=1; i<n; ++i){
 90             x=ri(), y=ri(), z=ri();
 91             addedge(x, y, z);
 92         }
 93         int s=1, far1, far2;
 94         maxdist=0, dfs(s, 0, 0);
 95         far1=maxdistpos;
 96         maxdist=0, dfs(far1, 0, 0);
 97         far2=maxdistpos;
 98         maxdist=0, dfs(far2, 0, 0);
 99         //for (int i=1; i<=n; ++i)
100         //printf("%d\n", val[i]);
101         int q=0;
102         for (int i=1; i<=n; ++i)
103             fmaxm[i][0]=fminm[i][0]=val[i];
104         for (int i=1; i<maxmi; ++i){
105             for (int j=1; j<=n-(1<<i)+1; ++j){
106                 fmaxm[j][i]=max(fmaxm[j][i-1], fmaxm[j+(1<<(i-1))][i-1]);
107                 fminm[j][i]=min(fminm[j][i-1], fminm[j+(1<<(i-1))][i-1]);
108             }
109         }
110         int h=1, t=1, maxm=0;
111         for (int i=0; i<m; ++i){
112             q=ri();
113             h=1, t=1, maxm=0;
114             while (t<=n){
115                 if (dvalue(h, t)<=q) ++t;
116                 else ++h;
117                 if ((t-h)>maxm) maxm=t-h;
118             }
119             printf("%d\n", maxm);
120         }
121     }
122     return 0;
123 }

 

posted @ 2017-08-29 09:14  pechpo  阅读(176)  评论(0编辑  收藏  举报