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);
}
}
}
浙公网安备 33010602011771号