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);
       }
    }
}

 

posted @ 2020-02-27 03:47  风生  阅读(112)  评论(0编辑  收藏  举报