HDU 6162 Ch’s gift

来源:互联网 发布:城市地图制作软件 编辑:程序博客网 时间:2024/06/05 06:09

HDU 6162 Ch’s gift

线段树,离线

题意

给一棵树,每次询问:uv两点间的路上(包括uv),点权在ab之间的所有点点权和。

思路

由于没有修改操作,一个显然的想法是离线处理所有问题
将询问拆成1-x,1-y,1-LCA(x,y),则处理的问题转化为从根到节点的链上的问题。
解决这个问题,我们可以在dfs时向treap插入当前的数,在退出时删除这个数,并且每次维护在该点上的答案。

两种思路,在线的树链剖分加主席树维护,离线的LCA加线段树/treap。我写的是离线LCA加线段树。线段树当成权值线段树用,所以离散化特别麻烦,可能treap更简单。

将每个询问拆开,u到v拆成:(1~u)+(1~v)-(2*1~LCA(u,v))+LCA(u,v)。如果LCA(u,v)权在询问上下界之间,就作为附加值加上,否则不加。

因为权值线段树要求范围是1到n,所以需要离散化,注意各种边界问题。

代码

#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<set>#include<iostream>#include<vector>#include<queue>#include<regex>#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define M(a,b) memset(a,b,sizeof(a))using namespace std;const int MAXN=100005;const int oo=0x3f3f3f3f;typedef long long LL;//树结构struct Edge{    int to, ne;}e[MAXN<<1];int head[MAXN], v[MAXN], edgenum;void addedge(int u, int v){    e[edgenum].to=v, e[edgenum].ne=head[u], head[u]=edgenum++;    e[edgenum].to=u, e[edgenum].ne=head[v], head[v]=edgenum++;}//LCAint parent[20][MAXN];int depth[MAXN];void ddfs(int v, int p, int d){    parent[0][v]=p;    depth[v]=d;    for(int i=head[v];~i;i=e[i].ne)    {        if(e[i].to!=p) ddfs(e[i].to, v, d+1);    }}void init(int V){    ddfs(1, -1, 0);    for(int k=0;k+1<20;k++)    {        for(int v=1;v<=V;v++)        {            if(parent[k][v]<0) parent[k+1][v]=-1;            else parent[k+1][v]=parent[k][parent[k][v]];        }    }}int lca(int u, int v){    if(depth[u]>depth[v]) swap(u, v);    for(int k=0;k<20;k++)    {        if((depth[v]-depth[u])>>k&1)            v=parent[k][v];    }    if(u==v) return u;    for(int k=20-1;k>=0;k--)    {        if(parent[k][u]!=parent[k][v])        {            u=parent[k][u];            v=parent[k][v];        }    }    return parent[0][u];}//点权与哈希struct Val{    LL val;    int i;    int ha;}val[MAXN];bool cmp1(Val a, Val b){    return a.val<b.val;}bool cmp2(Val a, Val b){    return a.i<b.i;}LL ha[MAXN];//分解询问struct Query{    int x, y;    int i, k;    LL res;    int ne;    int up, dw;    LL add;}q[MAXN*3];int qnum, headq[MAXN];//链式前向星储存询问//线段树LL stree[MAXN<<2];void pushup(int rt) { stree[rt]=stree[rt<<1]+stree[rt<<1|1]; }void build() { M(stree, 0); }void update(int pos, LL c, int l, int r, int rt){    if(l==r) { stree[rt]+=c;return; }    int mid=(l+r)>>1;    if(pos<=mid) update(pos, c, lson);    else update(pos, c, rson);    pushup(rt);}LL query(int L, int R, int l, int r, int rt){    if(L<=l&&r<=R) return stree[rt];    int mid=(l+r)>>1;    LL res=0;    if(L<=mid) res+=query(L, R, lson);    if(mid<R) res+=query(L, R, rson);    return res;}//dfs的solvevoid dfs(int u, int fa, int n){    update(val[u].ha, val[u].val, 1, n, 1);    for(int i=headq[u];~i;i=q[i].ne)    {        int l=q[i].dw, r=q[i].up;        q[i].res=query(l, r, 1, n, 1);    }    for(int i=head[u];~i;i=e[i].ne)    {        int to=e[i].to;        if(to!=fa) dfs(to, u, n);    }    update(val[u].ha, -val[u].val, 1, n, 1);}int main(){    //freopen("in.txt", "r", stdin);    //freopen("ou.txt", "w", stdout);    int n, m;    while(scanf("%d%d", &n, &m)==2)    {        //初始化        edgenum=1, qnum=1;M(head, -1), M(headq, -1);        build();        //点权与哈希        for(int i=1;i<=n;i++)        {            scanf("%lld", &val[i].val), val[i].i=i;        }        sort(val+1, val+n+1, cmp1);        int tt=1;ha[tt]=val[1].val-1;tt++;//加前哨兵        val[1].ha=tt;ha[tt]=val[1].val;        for(int i=2;i<=n;i++)        {            if(val[i].val>val[i-1].val) val[i].ha=++tt, ha[tt]=val[i].val;            else val[i].ha=tt;        }        sort(val+1, val+n+1, cmp2);        //树结构        for(int i=1;i<n;i++)        {            int u, v;scanf("%d%d", &u, &v);            addedge(u, v);        }        init(n);//LCA初始化        //分解询问        for(int i=1;i<=m;i++)        {            int x, y, up, dw;scanf("%d%d%d%d", &x, &y, &dw, &up);            int u=lca(x, y);            q[qnum].x=1, q[qnum].y=x, q[qnum].i=i, q[qnum].k=1;            q[qnum].dw=lower_bound(ha+1, ha+1+tt, dw)-ha, q[qnum].up=lower_bound(ha+1, ha+1+tt, up)-ha;            if(up<ha[q[qnum].up]) q[qnum].up--;//注意特判上端点            q[qnum].ne=headq[x], headq[x]=qnum++;            q[qnum].x=1, q[qnum].y=y, q[qnum].i=i, q[qnum].k=1;            q[qnum].dw=lower_bound(ha+1, ha+1+tt, dw)-ha, q[qnum].up=lower_bound(ha+1, ha+1+tt, up)-ha;            if(up<ha[q[qnum].up]) q[qnum].up--;//注意特判上端点            q[qnum].ne=headq[y], headq[y]=qnum++;            q[qnum].x=1, q[qnum].y=u, q[qnum].i=i, q[qnum].k=-1;            q[qnum].dw=lower_bound(ha+1, ha+1+tt, dw)-ha, q[qnum].up=lower_bound(ha+1, ha+1+tt, up)-ha;            if(up<ha[q[qnum].up]) q[qnum].up--;//注意特判上端点            q[qnum].ne=headq[u], headq[u]=qnum++;            q[qnum-1].add=((val[u].val>=dw&&val[u].val<=up) ? val[u].val : 0);//是否附加LCA的权        }        dfs(1, -1, tt);        for(int i=1;i<=3*m;i+=3)        {            LL ans=q[i].res+q[i+1].res-2*q[i+2].res+q[i+2].add;            printf("%lld%c", ans, i==3*m-2 ? '\n' : ' ');        }    }    //system("pause");    return 0;}