题目大意:
给定一棵$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 ",ans); 79 } 80 for(int i=1;i<=n;i++) e[i].clear(); 81 } 82 }