SPOJ TTM To the moon(主席树+区间操作)

转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

题目:给定一个序列,查询当前区间和,历史某个时期的区间和,以前区间修改,时间回滚操作
http://www.spoj.com/problems/TTM/ 
只要搞过可持久化线段树,就会觉得这题其实不难吧。。。
按时间,建立主席树,在上一时间段的基础上,进行区间更新,生成新的主席树。
查询历史区间什么的就直接查询那棵主席树,时间回滚都很简单。
但是实现起来就DT了。。。。
写完也很轻松。。。和之前做的主席树差不多
唯独这是区间更新。。。问题就在这了。。。
和线段树上的区间操作累似,对于线段加了lazy操作。
问题就在:如果当前区间更新,加入lazy,按理是不需要更新子节点的,之后直接push_down就行了
这是普通线段树的做法
但是如果当前区间的左右孩子还是原来的,那么在查询的时候,就容易push_down之后更新了历史版本
在这里错了好久,囧。。。。
但是又不能直接更新到所有叶子节点,那就相当于n棵线段树了。。。n*n*lgn左右的内存,吃不消。。
最后只能先指向原来的,但是在父节点上打上标记,表示如果要push_down的话,两个左右孩子都是历史版本,不能直接更新
那在push_down之前先判断是否是虚节点,如果是的话,就新建两个节点,然后再更新。。。
勉强搞过去了。。。相比于xiaodao的标程来说,内存多了好多。。。。(他是动态的)
#include<iostream>  
#include<cstdio>  
#include<map>  
#include<cstring>  
#include<cmath>  
#include<vector>  
#include<algorithm>  
#include<set>  
#include<stack>
#include<string>  
#include<ctime>
#include<queue>  
#include<cassert>
#define inf 1000000005  
#define M 10000005 
#define N 110005
#define maxn 210005  
#define eps 1e-8
#define zero(a) fabs(a)<eps  
#define Min(a,b) ((a)<(b)?(a):(b))  
#define Max(a,b) ((a)>(b)?(a):(b))  
#define pb(a) push_back(a)  
#define mp(a,b) make_pair(a,b)  
#define mem(a,b) memset(a,b,sizeof(a))  
#define LL long long  
#define MOD 1000000007
#define sqr(a) ((a)*(a))  
#define Key_value ch[ch[root][1]][0]  
#define test puts("OK");  
#define pi acos(-1.0)
#define lowbit(x) ((-(x))&(x))
#pragma comment(linker, "/STACK:1024000000,1024000000")  
using namespace std;
int n,q,a[N];
int T[N],tot,lson[M],rson[M],lazy[M],mark[M];
LL sum[M];
void push_up(int root){
    sum[root]=sum[lson[root]]+sum[rson[root]];
}
void push_down(int root,int l,int r){
    if(mark[root]){
        sum[tot]=sum[lson[root]];
        lazy[tot]=lazy[lson[root]];
        lson[tot]=lson[lson[root]];
        rson[tot]=rson[lson[root]];
        lson[root]=tot++;
        sum[tot]=sum[rson[root]];
        lazy[tot]=lazy[rson[root]];
        lson[tot]=lson[rson[root]];
        rson[tot]=rson[rson[root]];
        rson[root]=tot++;
        mark[lson[root]]=mark[rson[root]]=1;
        mark[root]=0;
    }
    if(lazy[root]){
        int m=(l+r)>>1;
        lazy[lson[root]]+=lazy[root];
        lazy[rson[root]]+=lazy[root];
        sum[lson[root]]+=(LL)lazy[root]*(m-l+1);
        sum[rson[root]]+=(LL)lazy[root]*(r-m);
        lazy[root]=0;
    }
}
int bulid(int l,int r){
    int root=tot++;
    lazy[root]=mark[root]=0;
    if(l==r){
        sum[root]=a[l];
        return root;
    }
    int m=(l+r)>>1;
    lson[root]=bulid(l,m);
    rson[root]=bulid(m+1,r);
    push_up(root);
    return root;
}
int update(int root,int L,int R,int l,int r,int val){
    int newroot=tot++;
    if(L==l&&R==r){
        lazy[newroot]=lazy[root]+val;
        sum[newroot]=sum[root]+(LL)val*(r-l+1);
        if(l!=r){
            lson[newroot]=lson[root];
            rson[newroot]=rson[root];
            mark[newroot]=1;
        }
        return newroot;
    } 
    lazy[newroot]=0;
    sum[newroot]=0;
    mark[newroot]=0;
    push_down(root,L,R);
    int m=(L+R)>>1;
    if(r<=m){
        lson[newroot]=update(lson[root],L,m,l,r,val);
        rson[newroot]=rson[root];
    }
    else if(l>m){
        lson[newroot]=lson[root];
        rson[newroot]=update(rson[root],m+1,R,l,r,val);
    }
    else{
        lson[newroot]=update(lson[root],L,m,l,m,val);
        rson[newroot]=update(rson[root],m+1,R,m+1,r,val);
    }
    push_up(newroot);
    return newroot;
}
LL query(int root,int L,int R,int l,int r){
    if(L==l&&R==r) return sum[root];
    push_down(root,L,R);
    int m=(L+R)>>1;
    if(r<=m) return query(lson[root],L,m,l,r);
    else if(l>m) return query(rson[root],m+1,R,l,r);
    else return (LL)query(lson[root],L,m,l,m)+query(rson[root],m+1,R,m+1,r);
}
void debug(int root,int l,int r){  
    cout<<l<<" "<<r<<" "<<sum[root]<<endl; 
    push_down(root,l,r); 
    if(l!=r){  
        int m=(l+r)>>1;  
        debug(lson[root],l,m);  
        debug(rson[root],m+1,r);  
    }  
}  
int main(){
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    while(scanf("%d%d",&n,&q)!=EOF){
        tot=0;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        T[0]=bulid(1,n);
        int Time=0;
        while(q--){
            char str[5];
            scanf("%s",str);
            int l,r,k;
            if(str[0]=='Q'){
                scanf("%d%d",&l,&r);
                printf("%lld\n",query(T[Time],1,n,l,r));
            }
            else if(str[0]=='H'){
                scanf("%d%d%d",&l,&r,&k);
                printf("%lld\n",query(T[k],1,n,l,r));
            }
            else if(str[0]=='C'){
                scanf("%d%d%d",&l,&r,&k);
                T[Time+1]=update(T[Time],1,n,l,r,k);
                Time++;
            }
            else{
                scanf("%d",&k);
                Time=k;
            }
        }
    }
    return 0;
}




你可能感兴趣的:(SPOJ TTM To the moon(主席树+区间操作))