http://acm.hdu.edu.cn/showproblem.php?pid=6162php
題目大意:已知樹上的每一個節點的值和節點之間的關係建成了一棵樹,如今查詢節點u到節點v的最短路徑上的節點值在l到r之間的節點值得和node
解題思路:套用樹鏈剖分的模板可以獲得樹上的鏈並把鏈上的節點進行了從新的定義(即在同一條鏈上的節點序列是連續的)。而後對於從新定義的節點進行建樹。樹有三個關鍵詞,minn,maxx和sum。在查詢時對從新定義的節點進行查詢(即對u到v所通過的每條鏈分別進行查詢)就能獲得查詢結果。c++
AC代碼:數組
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <map> 5 #include <vector> 6 #include <bits/stdc++.h> 7 using namespace std; 8 const int MAXN = 100010; 9 struct Edge 10 { 11 int to,next; 12 } edge[MAXN*2]; 13 int head[MAXN],tot; 14 15 int top[MAXN];//top[v]表示v所在的重鏈的頂端節點 16 int fa[MAXN]; //父親節點 17 int deep[MAXN];//深度 18 int num[MAXN];//num[v]表示以v爲根的子樹的節點數 19 int p[MAXN];//p[v]表示v與其父親節點的連邊在線段樹中的位置 20 int fp[MAXN];//和p數組相反 21 int son[MAXN];//重兒子 22 int pos; 23 24 25 void init() 26 { 27 tot = 0; 28 memset(head,-1,sizeof(head)); 29 pos = 1;//序號實際上是從1開始? 30 memset(son,-1,sizeof(son)); 31 } 32 void addedge(int u,int v) 33 { 34 edge[tot].to = v; 35 edge[tot].next = head[u]; 36 head[u] = tot++; 37 } 38 void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son 39 { 40 deep[u] = d; 41 fa[u] = pre; 42 num[u] = 1; 43 for(int i = head[u]; i != -1; i = edge[i].next) 44 { 45 int v = edge[i].to; 46 //由於路徑是雙向的,因此不能等於父及誒單 47 if(v != pre) 48 { 49 //先遞歸地找到兒子節點的深度,父節點,子節點數目等信息 50 dfs1(v,u,d+1); 51 //更新u節點的兒子數目 52 num[u] += num[v]; 53 if(son[u] == -1 || num[v] > num[son[u]])//求出重兒子 54 son[u] = v; 55 } 56 } 57 } 58 59 //由於對於輕兒子來講,top[u]=u,對於重兒子來講,若是son[v]!=-1,那麼top[v]=top[son[v]] 60 void getpos(int u,int sp) //第二遍dfs求出top和p 61 { 62 top[u] = sp; 63 //先找重兒子 64 if(son[u] != -1) 65 { 66 //把邊的位置標記一下 67 p[u] = pos++; 68 //fp至關因而p的反函數? 69 fp[p[u]] = u; 70 //更新重兒子 71 getpos(son[u],sp); 72 } 73 //若是到了葉子節點 74 else 75 { 76 //再也不向下dfs 77 p[u] = pos++; 78 fp[p[u]] = u; 79 return; 80 } 81 //更新其餘的節點 82 for(int i = head[u] ; i != -1; i = edge[i].next) 83 { 84 int v = edge[i].to; 85 if(v != son[u] && v != fa[u]) 86 getpos(v,v); 87 } 88 } 89 struct node 90 { 91 int maxx,minn; 92 long long sum; 93 }a[MAXN<<2]; 94 long long val[MAXN]; 95 int s,t,ut,dt; 96 int n,m; 97 void push_up(int k) 98 { 99 a[k].minn=min(a[k*2].minn,a[k*2+1].minn); 100 a[k].maxx=max(a[k*2].maxx,a[k*2+1].maxx); 101 a[k].sum=a[k*2].sum+a[k*2+1].sum; 102 } 103 void build(int l,int r,int k) 104 { 105 if(l==r) 106 { 107 a[k].maxx=a[k].minn=a[k].sum=val[fp[l]]; 108 return ; 109 } 110 int mid=(l+r)/2; 111 build(l,mid,k*2); 112 build(mid+1,r,k*2+1); 113 push_up(k); 114 } 115 long long query(int L,int R,int l,int r,int k) 116 { 117 int mid=(l+r)/2; 118 if(L<=l&&r<=R) 119 { 120 if(ut<=a[k].minn&&a[k].maxx<=dt) 121 { 122 return a[k].sum; 123 } 124 if(a[k].minn>dt||a[k].maxx<ut) 125 return 0LL; 126 return query(L,R,l,mid,k*2)+query(L,R,mid+1,r,k*2+1); 127 } 128 long long ans=0; 129 if(L<=mid) ans+=query(L,R,l,mid,k*2); 130 if(R>mid) ans+=query(L,R,mid+1,r,k*2+1); 131 return ans; 132 } 133 long long solve(int u,int v) 134 { 135 int f1=top[u]; 136 int f2=top[v]; 137 long long ans=0; 138 while(f1!=f2) 139 { 140 if(deep[f1]<deep[f2]) 141 { 142 swap(f1,f2); 143 swap(u,v); 144 } 145 ans+=query(p[f1],p[u],1,n,1); 146 u=fa[f1]; 147 f1=top[u]; 148 } 149 if(deep[v]<deep[u]) 150 { 151 swap(u,v); 152 } 153 ans+=query(p[u],p[v],1,n,1); 154 return ans; 155 } 156 int main() 157 { 158 while(~scanf("%d%d",&n,&m)) 159 { 160 for(int i=1;i<=n;i++) 161 scanf("%lld",&val[i]); 162 int x,y; 163 init(); 164 for(int i=1;i<n;i++) 165 { 166 scanf("%d%d",&x,&y); 167 addedge(x,y); 168 addedge(y,x); 169 } 170 dfs1(1,-1,0); 171 getpos(1,1); 172 build(1,n,1); 173 // for(int i=1;i<=n;i++) 174 // printf("%d = %d\n",i,fp[i]); 175 176 for(int i=0;i<m;i++) 177 { 178 scanf("%d%d%d%d",&s,&t,&ut,&dt); 179 val[i]=solve(s,t); 180 } 181 for(int i=0;i<m;i++) 182 { 183 if(i==0) 184 printf("%lld",val[i]); 185 else 186 printf(" %lld",val[i]); 187 } 188 printf("\n"); 189 } 190 return 0; 191 }