SPOJ - TTM 主席树

给你一个系列\(a[1...n]\),要求可以区间求和,区间更新,也可以回溯过去

经典的主席树板子题,很久以前做的题了,代码太丑回炉重写
PS.题目标题To The Moon也是我最喜欢的游戏之一

这回纯手写(美化)了一遍,意外踩坑了orz

1.不考虑空间开销可使用确实可以pushdown而不使用标记永久化,具体可以pushdown的时候另开左右儿子新节点

2.一个简易可行的节点回收方案是每一个时间戳记录最后一个更新到的节点id

3.可持久化标记是某节点的lazy表示该节点以下的懒惰标记,注意不动态更新sum只更lazy是无法保证上传正确的(曾经天真的以为..)

4.注意了lazy直接打到sum永久化之后还需注意不要pushup sum值,否则就是把下面的标记化的sum传上去等价于破坏标记.敲板子一般不会注意,自己手写debug了很久

明天开坑BZOJ

#include<bits/stdc++.h>
#include<unordered_map>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rrep(i,j,k) for(int i=j;i>=k;i--)
#define erep(i,u) for(int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
using namespace std;
const int MAXN = 1e5+11;
typedef long long ll;
ll read(){
    ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int a[MAXN];
struct FST{
    int lc[MAXN<<5],rc[MAXN<<5],delta[MAXN<<5];
    ll sum[MAXN<<5];
    int T[MAXN],ed[MAXN],tot;
    void init(){
        tot=0;
    }
    void pu(int o){
        sum[o]=sum[lc[o]]+sum[rc[o]];
    }
    int build(int l,int r){
        int cur=++tot;
        delta[cur]=0;
        if(l==r){
            sum[cur]=a[l];
            lc[cur]=rc[cur]=0;
            return cur;
        }
        int mid=l+r>>1;
        lc[cur]=build(l,mid);
        rc[cur]=build(mid+1,r);
        pu(cur);
        return cur;
    }
    int update(int old,int l,int r,int L,int R,int v){
        int cur=++tot;
        delta[cur]=delta[old];
        sum[cur]=sum[old];
        sum[cur]+=(ll)(min(R,r)-max(L,l)+1)*v;
        lc[cur]=lc[old];
        rc[cur]=rc[old];
        if(L<=l&&r<=R){
            delta[cur]+=v;
            return cur;
        }
        int mid=l+r>>1;
        if(L<=mid)lc[cur]=update(lc[old],l,mid,L,R,v);
        if(R>mid)rc[cur]=update(rc[old],mid+1,r,L,R,v);
        //have no pushUp!!!!!!!!!!!
        return cur;
    }
    ll query(int o,int l,int r,int L,int R){
        if(L<=l&&r<=R) return sum[o];
        int mid=l+r>>1;
        ll ans=(ll)(min(r,R)-max(L,l)+1)*delta[o];
        if(L<=mid) ans+=query(lc[o],l,mid,L,R);
        if(R>mid) ans+=query(rc[o],mid+1,r,L,R);
        return ans;
    }
}fst;
int main(){
    int n,m;
    bool flag=0;
    while(cin>>n>>m){
        if(flag==0) flag=1;
        else printf("\n");
        rep(i,1,n) a[i]=read();
        fst.init();
        fst.T[0]=fst.build(1,n);
        int now=0;fst.ed[now]=fst.tot;
        char str[1<<5];
        rep(i,1,m){
            scanf("%s",str);
            if(str[0]=='C'){
                int l=read();
                int r=read();
                int d=read();
                fst.T[now+1]=fst.update(fst.T[now],1,n,l,r,d); 
                now++; fst.ed[now]=fst.tot;
            }else if(str[0]=='Q'){
                int l=read();
                int r=read();
                println(fst.query(fst.T[now],1,n,l,r));
            }else if(str[0]=='H'){
                int l=read();
                int r=read();
                int t=read();
                println(fst.query(fst.T[t],1,n,l,r));
            }else{
                int t=read();
                now=t;fst.tot=fst.ed[t];
            }
        }
    }
    return 0;
}

HDU 2665
静态区间第k大
简单作差主席树即可

#include<bits/stdc++.h>
#include<unordered_map>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define rrep(i,j,k) for(int i=j;i>=k;i--)
#define erep(i,u) for(int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
using namespace std;
const int MAXN = 1e5+11;
typedef long long ll;
ll read(){
    ll x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct FST{
    int num[MAXN<<5];
    int T[MAXN],tot;
    int lc[MAXN<<5],rc[MAXN<<5];
    void init(){tot=0;}
    void pu(int o){
        num[o]=num[lc[o]]+num[rc[o]];
    }
    int build(int l,int r){
        int cur=++tot;
        num[cur]=lc[cur]=rc[cur]=0;
        if(l==r) return cur;
        int mid=l+r>>1;
        lc[cur]=build(l,mid);
        rc[cur]=build(mid+1,r);
        return cur;
    }
    void copy(int cur,int old){
        num[cur]=num[old];
        lc[cur]=lc[old];
        rc[cur]=rc[old];
    }
    int update(int old,int l,int r,int k){
        int cur=++tot;
        copy(cur,old);
        if(l==r){
            num[cur]++;
            return cur;
        }
        int mid=l+r>>1;
        if(k<=mid) lc[cur]=update(lc[old],l,mid,k);
        else rc[cur]=update(rc[old],mid+1,r,k);
        pu(cur);
        return cur;
    }
    int query(int st,int ed,int l,int r,int k){
        while(1){
            if(l==r) return l;
            int t1=num[lc[ed]]-num[lc[st]];
            if(k>t1){
                k-=t1;
                ed=rc[ed];
                st=rc[st];
                l=(l+r>>1);l++;
            }else{
                ed=lc[ed];
                st=lc[st];
                r=(l+r>>1);
            }
        }
    }
}fst;
int a[MAXN],b[MAXN],c[MAXN];
unordered_map<int,int> mp;
int main(){
    int n,m,T=read();
    while(T--){
        n=read(); m=read(); mp.clear();
        rep(i,1,n) b[i]=a[i]=read();
        sort(b+1,b+1+n);
        int nn=unique(b+1,b+1+n)-b-1;
        rep(i,1,n) c[i]=lower_bound(b+1,b+1+nn,a[i])-b;
        rep(i,1,n) mp[c[i]]=a[i];
        fst.init(); fst.T[0]=fst.build(1,nn);
        rep(i,1,n) fst.T[i]=fst.update(fst.T[i-1],1,nn,c[i]);
        while(m--){
            int st=read();st--;
            int ed=read();
            int k=read();
            println(mp[fst.query(fst.T[st],fst.T[ed],1,nn,k)]);
        }
    }
    return 0;
}
posted @ 2018-07-17 02:17  Caturra  阅读(159)  评论(0编辑  收藏  举报