Ch’s gift HDU6162
http://acm.hdu.edu.cn/showproblem.php?pid=6162
求树上两点之间的路径。
这个可以想到树链
那么现在的问题就可以转换为,如何在给定区间[l,r]中求的[ans1,ans2]之间的和。
简单的想法就是维护一个区间的最大值和最小值。
然后查询的时候,稍微注意一下。即可。
#include"stdio.h" #include"string.h" #include"algorithm" using namespace std; typedef long long ll; const int N = 200010; int n,q,root; int head[N],ver[N],Next[N],tot;///树的结构存储 ll val[N];///存储每个结点的信息 int d[N],son[N],far[N],Size[N];///结点的深度,重儿子,祖先 ll sum[N * 4],maxx[N * 4],minx[N * 4];///线段树上的结点值,maxx,sum值 int dfn[N],top[N],id[N];///存储dfs序,top是条链的祖先,id是每个结点在dfn中序列的下标位置 int cnt;///表示的是dfs序列的最后一个位置 int laze[N * 4],now[N * 4]; void add(int x,int y){ ///添加树边 ver[++ tot] = y; Next[tot] = head[x]; head[x] = tot; } void Build_Tree(int id,int l,int r) { laze[id] = now[id] = 0; if(l == r) { laze[id] = 0; now[id] = 0; maxx[id] = minx[id] = val[dfn[l]]; sum[id] = val[dfn[l]]; return ; } int mid = (l + r) >> 1; Build_Tree(id * 2,l,mid); Build_Tree(id * 2 + 1,mid + 1,r); sum[id] = sum[id * 2] + sum[id * 2 + 1]; maxx[id] = max(maxx[id * 2],maxx[id * 2 + 1]); minx[id] = min(minx[id * 2],minx[id * 2 + 1]); return ; } ll Query_sum(int id,int L,int R,int l,int r,ll lx,ll rx)///查询[l,r]区间和 { if(L > r || R < l) return 0; if(l <= L && r >= R && minx[id] >= lx && maxx[id] <= rx) { return sum[id]; } else if(L == R) return 0; int mid = (L + R) >> 1; ll ans = Query_sum(id * 2,L,mid,l,r,lx,rx) + Query_sum(id * 2 + 1,mid + 1,R,l,r,lx,rx); return ans; } void dfs1(int u,int f,int dep)///dfs1指在处理d数组,son数组,far数组,Size数组 { d[u] = dep; far[u] = f; Size[u] = 1; son[u] = -1; for(int i = head[u]; i; i = Next[i]){ int v = ver[i]; if(v == f) continue; dfs1(v,u,dep+1); Size[u] += Size[v]; if(son[u] == -1 || Size[son[u]] < Size[v]) son[u] = v; } } void dfs2(int u,int T)///旨在处理重链,和dfs序列 { dfn[++ cnt] = u;id[u] = cnt; top[u] = T; if(son[u] == -1) return ; dfs2(son[u],T); for(int i = head[u]; i; i = Next[i]){ int v = ver[i]; if(v != son[u] && v != far[u]){ dfs2(v,v); } } } ll Query(int u,int v,ll lx,ll rx) { int fu = top[u],fv = top[v]; ll ans = 0; while(fu != fv) { if(d[fu] >= d[fv]) { ans += Query_sum(1,1,n,id[fu],id[u],lx,rx); u = far[fu]; fu = top[u]; } else { ans += Query_sum(1,1,n,id[fv],id[v],lx,rx); v = far[fv]; fv = top[v]; } } if(id[u] < id[v]) ans += Query_sum(1,1,cnt,id[u],id[v],lx,rx); else ans += Query_sum(1,1,cnt,id[v],id[u],lx,rx); return ans; } void init() { memset(head,0,sizeof(head)); tot = 0; } int main() { while(~scanf("%d%d",&n,&q)) { init(); for(int i = 1; i <= n; i ++) { scanf("%lld",&val[i]); } for(int i = 1; i < n; i ++) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } cnt = 0;root = 1; dfs1(root,root,1); dfs2(root,root); Build_Tree(1,1,n); while(q --) { int u,v; scanf("%d%d",&u,&v); ll lx,rx; scanf("%lld%lld",&lx,&rx); ll ans = Query(u,v,lx,rx); if(q == 0) printf("%lld\n",ans); else printf("%lld ",ans); } } }