zoukankan      html  css  js  c++  java
  • 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
    ",ans);
               else printf("%lld ",ans);
           }
        }
    }
    
  • 相关阅读:
    opencv4显示与保存图片
    opencv播放视频
    opencv4.1.0环境配置
    lambda表达式
    基于范围的for循环
    可调用对象包装器std::function
    C++11的类型推导
    Datagridview 实现二维表头
    Linux内存相关sysfs、工具
    关于net core 站点通过iis部署,跨域配置遇到的问题
  • 原文地址:https://www.cnblogs.com/yrz001030/p/12370261.html
Copyright © 2011-2022 走看看