SPOJ TTM To The Moon 主席树区间操作+标记永久化

Problem

SPOJ

Solution

这就没有什么好缩的了,板子题一道,只不过用了标记永久化的思想,就比较方便一些咯

Code

#include 
#define pushup(x) sum[x]=sum[lc[x]]+sum[rc[x]]
using namespace std;
typedef long long ll;
const int maxn=100010,maxm=10000010;
int n,m,tot,now,rt[maxn],lc[maxm],rc[maxm];
ll sum[maxm],add[maxm];
char op[5];
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return xvoid build(int l,int r,int &rt)
{
    rt=++tot;
    if(l==r){read(sum[rt]);return ;}
    int m=(l+r)>>1;
    build(l,m,lc[rt]);
    build(m+1,r,rc[rt]);
    pushup(rt);
}
void update(int l,int r,int L,int R,int val,int &rt)
{
    ++tot;lc[tot]=lc[rt];rc[tot]=rc[rt];
    add[tot]=add[rt];sum[tot]=sum[rt];rt=tot;
    if(L<=l&&r<=R){add[rt]+=val;return ;}
    sum[rt]+=(ll)val*(min(R,r)-max(L,l)+1);
    int m=(l+r)>>1;
    if(L<=m) update(l,m,L,R,val,lc[rt]);
    if(m1,r,L,R,val,rc[rt]);
}
ll query(int l,int r,int L,int R,int rt)
{
    ll res=(ll)add[rt]*(min(R,r)-max(L,l)+1);
    if(L<=l&&r<=R) return sum[rt]+res;
    int m=(l+r)>>1;
    if(L<=m) res+=query(l,m,L,R,lc[rt]);
    if(m1,r,L,R,rc[rt]);
    return res;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    int x,y,d;
    read(n);read(m);
    build(1,n,rt[0]);
    while(m--)
    {
        scanf("%s",op);
        if(op[0]=='Q'){read(x);read(y);printf("%lld\n",query(1,n,x,y,rt[now]));}
        else if(op[0]=='C')
        {
            read(x);read(y);read(d);
            rt[now+1]=rt[now];now++;
            update(1,n,x,y,d,rt[now]);
        }
        else if(op[0]=='H')
        {
            read(x);read(y);read(d);
            printf("%lld\n",query(1,n,x,y,rt[d]));
        }
        else if(op[0]=='B') read(now),tot=rt[now+1]-1;
    }
    return 0;
}

你可能感兴趣的:(主席树)