hdu-4348-To the moon-离线处理 or 主席树区间更新

题意:

-------------------------------------------------------------------------------------------------------------------------



第一种解法,按离线建树,写起来比较简单:

类似  http://blog.csdn.net/viphong/article/details/52264179


也就是根据询问之间的先后顺序建立树,然后dfs一遍,在过程中求解。注意建立的是询问之间的关系,而不时间的关系

处理询问只需要用到一个线段树区间更新即可

-------------------------------------------------------------------------------------------------------------------------


第二种解法

用主席树实现线段树的区间更新和查询,并支持历史版本信息的访问。

此处为了避免MLE,把区间更新的lazy标记去掉,改成维护sum和fix两个信息的单点更新实现区间更新,思想类似于前缀和

就是对于add(l,r,val)的操作变成

add_sum_fix(l,val)

{

sum[i]+=val;

fix[i]+=(l-1)*val;

}

add_sum_fix(r+1,val)

  

那么我们查询【l,r】只需要查询

ll query(int t,int x)
{
    if (x<1) return 0;
    ll sum=querysum(t,1,n,1,x);
    ll ff=queryfix(t,1,n,1,x);
    return sum*x-ff;
}


 




离线按询问建树的代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <bitset>
#include <vector>
#include <iostream>
using namespace std;

const double pi=acos(-1.0);
double eps=0.000001;
typedef long long  ll;
const int N = 100005  ;
ll ans[100005];
struct TREE
{
    ll  sum[4*N], add[4*N] ;
    void pushDown(int i, int l, int r)		//把i节点的延迟标记传递到左右儿子节点
    {
        if(add[i] != 0)
        {
            int mid = (l + r) >> 1;
            add[i << 1] += add[i];
            sum[i << 1] += (mid - l + 1) * add[i];  //[l, mid]代表左儿子区间
            add[i << 1 | 1] += add[i];
            sum[i << 1 | 1] += (r - mid) * add[i];  //[mid + 1, r]代表右儿子区间
            add[i] = 0;
        }
    }
    void update(int i, int l, int r, int ql, int qr, ll val) //更新区间为qlqr,当前区间为l,r,代表当前区间和的节点为i,更新值为val,
    {
        if(l > qr || ql > r)		//更新区间不在当前区间内
            return ;
        if(l >= ql && r <= qr)	//要更新的区间把当前区间完全包括,则把当前整个区间+val,然后返回上一层
        {
            sum[i] +=1LL* (r - l + 1) * val;
            add[i] += val;
            return ;
        }
        pushDown(i, l, r);			//如果上面没reutrn 表示要往左右儿子区间查询,所以把延迟标记放下去
        int mid = (l + r) >> 1;
        update(i << 1, l, mid, ql, qr, val);
        update(i << 1 | 1, mid + 1, r, ql, qr, val);
        sum[i] = sum[i << 1] + sum[i << 1 | 1];
    }

    ll query(int i, int l, int r, int ql, int qr)	 //查询区间为qlqr,当前区间为l,r,代表当前区间和的节点为i
    {
        if(l > qr || ql > r)
            return 0;
        if(l >= ql && r <= qr)
            return sum[i];
        pushDown(i, l, r);				//同update
        int mid =( l + r) >> 1;
        return query(i << 1, l, mid, ql, qr)
               + query(i << 1 | 1, mid + 1, r, ql, qr);
    }
    void init()
    {
        memset(sum,0,sizeof sum);
        memset(add,0,sizeof add);
    }
} tp;
struct node
{
    int  x,y,z;
    char kind;
};

vector<int >mp[100050];
node tt[100050];
int n, q;
void deal(int x)
{
    char k=tt[x].kind;
    int i=tt[x].x;
    int j=tt[x].y;
    int z=tt[x].z;
    if (k=='C')
        tp.update(1,1,n,i,j,z);
    if (k=='Q')
        ans[x]=tp.query(1,1,n,i,j);
    if (k=='H')
        ans[x]=tp.query(1,1,n,i,j);
}
void redeal(int x)
{
    char k=tt[x].kind;
    int i=tt[x].x;
    int j=tt[x].y;
    int z=tt[x].z;
    tp.update(1,1,n,i,j,-z);
}
bool cmp(int a,int b)
{
    return tt[a].kind>tt[b].kind;
}
void dfs(int x)
{
    if (x) deal(x);
    sort(mp[x].begin(),mp[x].end(),cmp);
    for (int i=0; i<mp[x].size(); i++)
    {
        int v=mp[x][i];
        dfs(v);
    }
    if (x&&tt[x].kind=='C')
        redeal(x);
}
int time_event[100005];
int main()
{
    int x;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        tp.init();
        for (int i=1; i<=n; i++)scanf("%d",&x),tp.update(1,1,n,i,i,x);
        for (int i=0; i<=q; i++) mp[i].clear();
        char op[5];
        int time=0;
        for (int i=1; i<=q; i++)
        {
            scanf("%s",op);
            tt[i].kind=op[0];
            if (op[0]=='C')
            {
                scanf("%d%d%d",&tt[i].x,&tt[i].y,&tt[i].z);
                mp[time_event[time]].push_back(i);
                time++;
                time_event[time]=i;
            }
            else if (op[0]=='H')
            {
                scanf("%d%d%d",&tt[i].x,&tt[i].y,&tt[i].z);
                mp[time_event[tt[i].z]].push_back(i);
            }
            else if (op[0]=='B')
            {
                scanf("%d",&tt[i].x);
                mp[time_event[tt[i].x]].push_back(i);
                time=tt[i].x;
            }
            else
            {
                scanf("%d%d",&tt[i].x,&tt[i].y);
                mp[ time_event[time]].push_back(i);

            }
        }
        dfs(0);
        for (int i=1; i<=q; i++)
            if (tt[i].kind=='Q'||tt[i].kind=='H')
                printf("%lld\n",ans[i]);
    }

    return 0;

}

主席树区间更新代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const int MAXNN=100005;
typedef long long ll;
#define w(i) T[(i)].w
#define fix(i) T[(i)].fix
#define ls(i) T[(i)].ls
#define rs(i) T[(i)].rs


int n,m;
struct node
{
    int ls,rs;
    ll w,fix;
} T[MAXNN*51];
ll aa[100005];

int root[MAXNN+50],sz;
int  build_tree(int l,int r)
{
    int t=++sz;
    T[t].w=T[t].fix=0;
    if (l==r) return t;
    int mid=(l+r)>>1;
    T[t].ls=build_tree(l,mid);
    T[t].rs=build_tree(mid+1,r);
    return t;
}
int  update(int i,int x,int val,int l,int r)
{
    T[++sz]=T[i];
    i=sz;
    if (l==r)
    {
        T[i].w+=val;
        T[i].fix+=1LL*(x-1)*val;
        return i;
    }
    int m=(l+r)>>1;
    if (x<=m) ls(i)=update(ls(i),x,val,l,m);
    else rs(i)=update(rs(i),x,val,m+1,r);

    T[i].w=w(ls(i))+w(rs(i));
    T[i].fix=fix(ls(i))+fix(rs(i));
    return i;
}

ll queryfix(int i,int l,int r,int ql,int qr )
{
    if (ql>r||qr<l) return 0;
    if (ql<=l&&qr>=r) return T[i].fix;
    int m=(l+r)>>1;
    return  queryfix(ls(i) ,l,m,ql,qr)
            + queryfix(rs(i),m+1,r,ql,qr);
}
ll querysum(int i ,int l,int r,int ql,int qr)
{
    if (ql>r||qr<l) return 0;
    if (ql<=l&&qr>=r) return T[i].w;
    int m=(l+r)>>1;
    return  querysum(ls(i) ,l,m,ql,qr)
            + querysum(rs(i),m+1,r,ql,qr);
}
void init()
{
    root[0]=0;
    sz=0;
}
ll query(int t,int x)
{
    if (x<1) return 0;
    ll sum=querysum(t,1,n,1,x);
    ll ff=queryfix(t,1,n,1,x);
    return sum*x-ff;
}
int main()
{
    //DO YOLO
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for (int i=1; i<=n; i++)
            scanf("%lld",&aa[i]),aa[i]+=aa[i-1];
        init();
        int time=0;

        root[time]=build_tree(1,n);
        char op[5];
        int x,y,z;
        for (int i=1; i<=m; i++)
        {
            scanf("%s",op);
            if (op[0]=='C')
            {
                scanf("%d%d%d",&x,&y,&z);
                root[time+1]=update(root[time],x,z,1,n);
                root[time+2]=update(root[time+1],y+1,-z,1,n);
                time+=2;
            }
            else if (op[0]=='Q')
            {
                scanf("%d%d",&x,&y);
                ll RR=query(root[time],y);
                ll LL=query(root[time],x-1);
                ll ans=RR-LL+aa[y]-aa[x-1];
                printf("%lld\n",ans);
            }
            else if (op[0]=='H')
            {
                scanf("%d%d%d",&x,&y,&z);
                ll RR=query(root[2*z],y);
                ll LL=query(root[2*z],x-1);
                ll ans=RR-LL+aa[y]-aa[x-1];
                printf("%lld\n",ans);
            }
            else
            {
                int z;
                scanf("%d",&z);
                time=z*2;
                sz=root[time+1]; //?????k
            }
        }
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值