HDU - 6162(Ch’s gift)

题目(B - Ch’s gift )

题目意思:

给定一棵树,树的节点上有权值。接下来会有q次查询。每次查询书上两个节点路径上经过的所有点(包括给出的两个点)权值在[a,b] 这个区间的数求和。每次都是查询这个 s,t,a,b。

解题思路:

按照官方给出的题解,离线+lca。

具体是这样:离线还是要的,我们需要查询s,t这条路径在区间 [a,b] 的数的和。假设 g(x,a,b):代表 树上节点为x的点到根节点这条路径上数字在[a,b] 这个闭区间的数的和。并且假设lca(x,y) 代表x加点与y节点的最近公共祖先。那么每次查询就是:$$g\left ( s,a,b \right )+g(t,a,b)-2*g(lca(s,t),a,b)$$

但是这样计算没有包括lca(s,t)这个点,我们应该特判这个点是否在[a,b]这个区间内部?如果在加上。

所以如何算出需要的g(x,a,b),因为需要的就只有3×q,这么多个。我们发现在遍历这棵树的时候,遍历到一个节点把这个点插入到一个数据结构。遍历完这个点,把这个点删除掉。那么每次遍历到某个点,数据结构里面的点都是这个点到根的所有数字,在这时候我们需要知道数据结构中的数在 [a,b] 这个区间的数字求和是多少?抽象一下,这个数据结构需:

  • 插入一个元素。
  • 删除一个元素。
  • 查询所有元素在[a,b]这个区间的数的和。

我们只需要三个操作。刚好线段树支持这些操作。听说平衡树可以,标程使用 Treap 来维护的。个人线段树用的多,所以就用了线段树。那么线段树节点就维护和,下面有是线段树部分,在结构体封装了。

现在还有 lca,这个的就用倍增随便搞搞。我的处理方法是读入数据,看需要的g(x,a,b)传到树的节点上。遍历树的时候如果有需要的就进行查询操作。

最后输出答案就好,细节可参考本人比较拙的代码。

#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <string.h>
#include <string>
#include <queue>
#include <map>


using namespace std;
typedef long long int LL;


const int maxn=1e5+10;

struct segtree 
{
    struct Node 
    {
        int lson,rson;
        LL sum;
    }T[maxn*32];
    int root,sz;
    int newnode()
    {
        sz++;
        T[sz].lson=T[sz].rson=-1;
        T[sz].sum=0;
        return sz;
    }
    void init()
    {
        sz=-1;
        root=newnode();
    }
    void insert(int& i,int l,int r,int val)
    {
        if(i==-1) i=newnode();
        T[i].sum+=val;
        if(l==r) return ;
        int mid=(l+r)>>1;
        if(val<=mid) insert(T[i].lson,l,mid,val);
        else insert(T[i].rson,mid+1,r,val);
    }
    void del(int& i,int l,int r,int val)
    {
        if(i==-1) i=newnode();
        T[i].sum-=val;
        if(l==r) return ;
        int mid=(l+r)>>1;
        if(val<=mid) del(T[i].lson,l,mid,val);
        else del(T[i].rson,mid+1,r,val);
    }
    LL query(int i,int l,int r,int ql,int qr)
    {
        if(i==-1) return 0;
        if(l==ql&&r==qr) return T[i].sum;
        int mid=(l+r)>>1;
        if(qr<=mid) return query(T[i].lson,l,mid,ql,qr);
        else if(ql>mid) return query(T[i].rson,mid+1,r,ql,qr);
        else return query(T[i].lson,l,mid,ql,mid)+query(T[i].rson,mid+1,r,mid+1,qr);
    }
}ac;


vector<int>G[maxn];
int treeval[maxn],fa[maxn][20],deep[maxn];
int n,m;
void dfs(int x,int pre)
{
    //printf("dfs x=%d\n",x);
    fa[x][0]=pre;
    deep[x]=deep[pre]+1;
    for(int i=1;i<20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=0;i<(int)G[x].size();i++)
    {
        int to=G[x][i];
        if(to==pre) continue;
        dfs(to,x);
    }
}
int lca(int x,int y)
{
    if (deep[x] < deep[y])
    {
        swap(x, y);
    }
    int delta = deep[x] - deep[y];
    for (int i = 0; i <= 23; ++i)
    {
        if ((delta >> i) & 1)
        {
            x = fa[x][i];
        }
    }
    if (x == y)
    {
        return x;
    }
    for (int i = 19;i>=0; --i)
    {
        if (fa[x][i] != fa[y][i])
        {
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    return fa[x][0];
}

struct Query 
{
    LL a,b;
    LL *p;
    Query(LL _a,LL _b,LL *_p) 
    {
        a=_a,b=_b;
        p=_p;
    }
};
struct Answer 
{
    LL s,t,lca,temp;
}ans[maxn];
vector<Query>need[maxn];
void df(int x,int pre)
{
   // printf("df  x=%d\n",x);
    ac.insert(ac.root,1,1e9,treeval[x]);
    for(int i=0;i<(int)need[x].size();i++)
    {
        
        LL *p,a=need[x][i].a,b=need[x][i].b;
        p=need[x][i].p;
        LL ans=ac.query(ac.root,1,1e9,a,b);
        *p=ans;
      //  printf("query x=%d a=%lld b=%lld ans=%lld\n",x,a,b,ans);
    }
    for(int i=0;i<(int)G[x].size();i++)
    {
        int to=G[x][i];
        if(to==pre) continue;
        df(to,x);
    }
    ac.del(ac.root,1,1e9,treeval[x]);
}
int main()
{
    while(scanf("%d%d",&n,&m)+1)
    {
        for(int i=1;i<=n;i++)
        {
            G[i].clear();
            need[i].clear();
            scanf("%d",&treeval[i]);
        }
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        deep[0]=0;
        dfs(1,0);
        for(int i=1;i<=m;i++)
        {
            int s,t,a,b;
            scanf("%d%d%d%d",&s,&t,&a,&b);
            int _lca=lca(s,t);
            //printf("s=%d t=%d lca=%d\n",s,t,_lca);
            need[s].push_back(Query(a,b,&ans[i].s));
            need[t].push_back(Query(a,b,&ans[i].t));
            need[_lca].push_back(Query(a,b,&ans[i].lca));
            if(treeval[_lca]>=a&&treeval[_lca]<=b) ans[i].temp=treeval[_lca];
            else ans[i].temp=0;
        }
        ac.init();
        df(1,0);
        for(int i=1;i<=m;i++)
        {
            //printf("s=%lld t=%lld lca=%lld\n",ans[i].s,ans[i].t,ans[i].lca);
            LL ff=ans[i].s+ans[i].t-2*ans[i].lca+ans[i].temp;
            printf(i==m?"%I64d\n":"%I64d ",ff);
        }
    }
    return 0;
}
posted @ 2017-09-10 20:00  Code-dream  阅读(225)  评论(0编辑  收藏  举报