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;
}

转载于:https://www.cnblogs.com/caturra/p/9321310.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值