hdu4714 Bob’s Race
http://acm.hdu.edu.cn/showproblem.php?pid=4123
给出一棵树,一个人从一个点开始跑,会跑到尽量远的叶子节点,现在问对于每一个询问q,最多能有多少标号连续的人跑,满足最长者减最短者不超过q。
这道题综合了三层,树的最远对,rmq,和单调队列。
首先尽量远就是要最远对,用直径的算法。然后是对于每一个q,从1~n作为右端点,用单调队列的思想求最长的区间,每次查询是否到达q一定要用rmq,我用线段树做,开始debug半天发现rt必须从1开始,后来又发现超时。
#include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<string> #include<cctype> #include<stack> #include<queue> #include<set> #include<sstream> #include<map> #include<ctime> using namespace std; #define For(i,k,n) for(int i=k;i<=n;i++) #define ForD(i,k,n) for(int i=n;i>=k;i--) #define Lson (u<<1) #define Rson ((u<<1)+1) #define MEM(a) memset(a,0,sizeof(a)); #define NEG(a) memset(a,-1,sizeof(a)); #define FILL(a) memset(a,0x3f,sizeof(a)); #define INF 0x3f3f3f3f #define LLINF 0x3f3f3f3f3f3f3f3f #define ll long long #define print(b,a) cout<<b<<"="<<a<<endl; #define printbin(b,a){int tmp=a;string s;do{s+=tmp%2+'0';tmp/=2;}while(tmp);reverse(s.begin(),s.end());cout<<"bin "<<b<<"="<<s<<endl;} #define printarr(i,a,f,b) {For(i,f,b) printf("%d ",a[i]); printf("\n");} #define fp freopen("in.txt","r",stdin) #define maxn 60000 struct edge { int v, w; }; int N,M; int f[maxn],g[maxn],h[maxn],longest[maxn]; int a[maxn]; int dp1[maxn][20]; int dp2[maxn][20]; int mm[maxn]; vector<edge>e[maxn]; void init() { For(i,1,N) e[i].clear(); NEG(f);NEG(g);NEG(h);NEG(longest); } int dfs(int root, int pre){ int est = 0, esti=-1, er=0; if(f[root]!=-1) return f[root]; if(e[root].empty()) { //printf("root=%d\n",root); return f[root] = 0; } int sz=e[root].size(); for(int i=0;i<sz;i++){ if(pre!=e[root][i].v){ if(dfs(e[root][i].v,root)+e[root][i].w>est){ est = f[e[root][i].v]+e[root][i].w; esti = i; } } } longest[root] = esti; sz=e[root].size(); for(int i=0;i<sz;i++){ if(pre!=e[root][i].v){ if(f[e[root][i].v]+e[root][i].w>er&&i!=longest[root]){ er = f[e[root][i].v]+e[root][i].w; } } } g[root] = er; return f[root] = est; } void dfs1(int root, int pre){ int sz=e[root].size(); for(int i=0;i<sz;i++){ if(pre!=e[root][i].v){ if(i!=longest[root]){ h[e[root][i].v] = max(h[root],f[root])+e[root][i].w; } else{ h[e[root][i].v] = max(h[root],g[root])+e[root][i].w; } dfs1(e[root][i].v,root); } } } void initRMQ() { mm[0] = -1; for(int i = 1;i <= N;i++) { mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1]; dp1[i][0] = a[i]; dp2[i][0] = a[i]; } for(int j = 1;j <= mm[N];j++) for(int i = 1;i + (1<<j) - 1 <= N;i++) { dp1[i][j] = max(dp1[i][j-1],dp1[i + (1<<(j-1))][j-1]); dp2[i][j] = min(dp2[i][j-1],dp2[i + (1<<(j-1))][j-1]); } } int rmq(int x,int y) { int k = mm[y-x+1]; return max(dp1[x][k],dp1[y-(1<<k)+1][k]) - min(dp2[x][k],dp2[y-(1<<k)+1][k]); } void solve() { For(i,1,N) { if(f[i]==-1) { f[i]=dfs(i,-1); h[i]=0;dfs1(i,-1); } } FILL(Min); NEG(Max); For(i,1,N) { a[i]=max(h[i],f[i]); // printf("a[%d]=%d\n",i,a[i]); } initRMQ(); int Q; For(i,1,M) { scanf("%d",&Q); int ans=0; int id=1; For(j,1,N) { while(id<=j&&rmq(id,j)>Q) id++; ans=max(ans,j-id+1); } printf("%d\n",ans); } } int main() { // fp; while(scanf("%d%d",&N,&M)==2&&!(N==0&&M==0)) { init(); For(i,1,N-1) { int u,v,w; scanf("%d %d %d",&u,&v,&w); e[u].push_back(edge{v,w}); e[v].push_back(edge{u,w}); } solve(); } return 0; }