*线段树&&主席树&&可持久化线段树

今天是2017/5/23,DCDCBigBig的第十一篇博文

啊。。。昨天真是太累了。。。把树链剖分先传上来了,用的还是线段树区间修改。然而我并没有传线段树。。。(所以说那份代码是py来的。。。)那这篇博文就多放点模板,给大家发发福利吧^_^

线段树1(单点修改)

//求区间最值
//n个元素,m个询问
//C x y 代表将第x个元素的值改为y
//D x y 代表在第x到第y个元素中找最大值 
//X x y 代表在第x到第y个元素中找最小值
//附带一个print函数,可以遍历并输出叶节点 
#include
#include
#include
#include
using namespace std;
struct tree_node{
    int maxn,minn;
}t[400001];
int n,m,x,y,a[100001];
char ord[5];
void build(int l,int r,int u){
    if(l==r){
        t[u].maxn=a[l];
        t[u].minn=a[l];
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,u*2);
    build(mid+1,r,u*2+1);
    t[u].maxn=max(t[u*2].maxn,t[u*2+1].maxn);
    t[u].minn=min(t[u*2].minn,t[u*2+1].minn);
}
void print(int l,int r,int u){
    if(l==r){
        printf("%d ",t[u].minn);
        return;
    }
    int mid=(l+r)/2;
    print(l,mid,u*2);
    print(mid+1,r,u*2+1);
}
void updata(int l,int r,int u,int x,int y){
    if(l==r){
        t[u].maxn=y;
        t[u].minn=y;
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid)updata(l,mid,u*2,x,y);
    else if(x>mid)updata(mid+1,r,u*2+1,x,y);
    t[u].maxn=max(t[u*2].maxn,t[u*2+1].maxn);
    t[u].minn=min(t[u*2].minn,t[u*2+1].minn);
}
int query_max(int l,int r,int u,int L,int R){
    if(l>=L&&r<=R){
        return t[u].maxn;
    }
    int mid=(l+r)/2,ans=-2147483647;
    if(L<=mid)ans=max(ans,query_max(l,mid,u*2,L,R));
    if(R>mid)ans=max(ans,query_max(mid+1,r,u*2+1,L,R));
    return ans;
}
int query_min(int l,int r,int u,int L,int R){
    if(l>=L&&r<=R){
        return t[u].minn;
    }
    int mid=(l+r)/2,ans=2147483647;
    if(L<=mid)ans=min(ans,query_min(l,mid,u*2,L,R));
    if(R>mid)ans=min(ans,query_min(mid+1,r,u*2+1,L,R));
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    build(1,n,1);
    for(int i=1;i<=m;i++){
        scanf("%s",ord);
        if(ord[0]=='P'){
            print(1,n,1);
            printf("\n");
            continue;
        }
        scanf("%d%d",&x,&y);
        if(ord[0]=='C'){
            updata(1,n,1,x,y);
        }
        if(ord[0]=='D'){
            printf("%d\n",query_max(1,n,1,x,y));
        }
        if(ord[0]=='X'){
            printf("%d\n",query_min(1,n,1,x,y));
        }
    }
    return 0;
}

线段树2(区间修改+lazy标记)

区间加值

ps:懒癌发作,不知道拖了几天才写好。。。

//区间求和+区间修改(区间加值版)
//类似地,n个元素、m个询问 
//Q x y表示询问xy的和 
//A x y z表示将xy的值全部加上z
#include
#include
#include
#include
using namespace std;
struct tree{
    int v,lazy;
}t[400001];
int n,m,x,y,z,a[100001];
char ord[5];
void pd(int u,int l,int r){
    if(t[u].lazy!=0){
        int mid=(l+r)/2;
        t[u*2].lazy+=t[u].lazy;
        t[u*2+1].lazy+=t[u].lazy;
        t[u*2].v+=t[u].lazy*(mid-l+1);
        t[u*2+1].v+=t[u].lazy*(r-mid);
        t[u].lazy=0;
    }
}
void build(int l,int r,int u){
    if(l==r){
        t[u].v=a[l];
        return;
    }
    int mid=(l+r)/2;
    t[u].lazy=0;
    build(l,mid,u*2);
    build(mid+1,r,u*2+1);
    t[u].v=t[u*2].v+t[u*2+1].v;
}
void updata(int l,int r,int u,int L,int R,int val){
    if(L<=l&&r<=R){
        t[u].lazy+=val;
        t[u].v+=val*(r-l+1);
        return;
    }
    pd(u,l,r);
    int mid=(l+r)/2;
    if(L<=mid)updata(l,mid,u*2,L,R,val);
    if(R>mid)updata(mid+1,r,u*2+1,L,R,val);
    t[u].v=t[u*2].v+t[u*2+1].v;
}
int query(int l,int r,int u,int L,int R){
    if(L<=l&&r<=R){
        return t[u].v;
    }
    pd(u,l,r);
    int mid=(l+r)/2,ans=0;
    if(L<=mid)ans+=query(l,mid,u*2,L,R);
    if(R>mid)ans+=query(mid+1,r,u*2+1,L,R);
    t[u].v=t[u*2].v+t[u*2+1].v;
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    build(1,n,1);
    for(int i=1;i<=m;i++){
        scanf("%s%d%d",ord,&x,&y);
        if(ord[0]=='A'){
            scanf("%d",&z);
            updata(1,n,1,x,y,z);
        }
        if(ord[0]=='Q'){
            printf("%d\n",query(1,n,1,x,y));
        }
    }
    return 0;
}
/*
5 5
1 2 3 4 5
Q 1 5
A 1 3 5
Q 1 5
A 3 5 -3
Q 1 5
*/

区间改值

//区间求和+区间修改(区间改值版)
//n个元素、m个询问 
//Q x y表示询问xy的和 
//C x y z表示将xy的值全部改成z
#include
#include
#include
#include
using namespace std;
struct tree{
    int v,lazy;
}t[400001];
int n,m,x,y,z,a[100001];
char ord[5];
void pd(int u,int l,int r){
    if(t[u].lazy!=0){
        int mid=(l+r)/2;
        t[u*2].lazy=t[u].lazy;
        t[u*2+1].lazy=t[u].lazy;
        t[u*2].v=t[u].lazy*(mid-l+1);
        t[u*2+1].v=t[u].lazy*(r-mid);
        t[u].lazy=0;
    }
}
void build(int l,int r,int u){
    if(l==r){
        t[u].v=a[l];
        return;
    }
    int mid=(l+r)/2;
    t[u].lazy=0;
    build(l,mid,u*2);
    build(mid+1,r,u*2+1);
    t[u].v=t[u*2].v+t[u*2+1].v;
}
void updata(int l,int r,int u,int L,int R,int val){
    if(L<=l&&r<=R){
        t[u].lazy=val;
        t[u].v=val*(r-l+1);
        return;
    }
    pd(u,l,r);
    int mid=(l+r)/2;
    if(L<=mid)updata(l,mid,u*2,L,R,val);
    if(R>mid)updata(mid+1,r,u*2+1,L,R,val);
    t[u].v=t[u*2].v+t[u*2+1].v;
}
int query(int l,int r,int u,int L,int R){
    if(L<=l&&r<=R){
        return t[u].v;
    }
    pd(u,l,r);
    int mid=(l+r)/2,ans=0;
    if(L<=mid)ans+=query(l,mid,u*2,L,R);
    if(R>mid)ans+=query(mid+1,r,u*2+1,L,R);
    t[u].v=t[u*2].v+t[u*2+1].v;
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    build(1,n,1);
    for(int i=1;i<=m;i++){
        scanf("%s%d%d",ord,&x,&y);
        if(ord[0]=='C'){
            scanf("%d",&z);
            updata(1,n,1,x,y,z);
        }
        if(ord[0]=='Q'){
            printf("%d\n",query(1,n,1,x,y));
        }
    }
    return 0;
}
/*
5 5
1 2 3 4 5
Q 1 5
C 1 3 5
Q 1 5
C 3 5 -3
Q 1 5
*/

可持久化线段树(单点修改)

//单点修改可持久化线段树(非主席树)
//给出n个数,q个询问
//每次询问形如 0 k l r 或 1 k i x
//表示询问第k个版本l到r之间的最大值或把第k个版本的第i个数改为x
//初始的n个数表示第一个版本 
#include
#include
#include
#include
using namespace std;
struct node{
    int mx,ls,rs;
}t[2000001];
int n,q,k,l,r,ord,cnt=0,tot=0,rt[100001],num[100001];
void build(int l,int r,int &u){
    if(!u)u=++tot;
    if(l==r){
        t[u].mx=num[l];
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,t[u].ls);
    build(mid+1,r,t[u].rs);
    t[u].mx=max(t[t[u].ls].mx,t[t[u].rs].mx);
}
void ins(int &k,int last,int l,int r,int p,int x){
    t[k=++tot].mx=t[last].mx;
    if(l==r){
        t[k].mx=x;
        return;
    }
    t[k].ls=t[last].ls;
    t[k].rs=t[last].rs;
    int mid=(l+r)/2;
    if(p<=mid)ins(t[k].ls,t[last].ls,l,mid,p,x);
    else ins(t[k].rs,t[last].rs,mid+1,r,p,x);
    t[k].mx=max(t[t[k].ls].mx,t[t[k].rs].mx);
}
int query(int &k,int l,int r,int L,int R){
    if(!k)return 0;
    if(L==l&&r==R){
        return t[k].mx;
    }
    int mid=(l+r)/2;
    if(R<=mid)return query(t[k].ls,l,mid,L,R);
    else if(L>mid)return query(t[k].rs,mid+1,r,L,R);
    else return max(query(t[k].ls,l,mid,L,mid),query(t[k].rs,mid+1,r,mid+1,R));
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&num[i]);
    }
    build(1,n,rt[++cnt]);
    for(int i=1;i<=q;i++){
        scanf("%d%d%d%d",&ord,&k,&l,&r);
        if(ord==1){
            ins(rt[++cnt],rt[k],1,n,l,r);
        }else{
            printf("%d\n",query(rt[k],1,n,l,r));
        }
    }
    return 0;
}

可持久化线段树(区间修改)

//hdu4348
//标记永久化是真的省空间!!! 
#include
#include
#include
#include
using namespace std;
typedef long long ll;
struct node{
    int ls,rs;
    ll v,lazy;
}t[5000001];
int n,m,k,l,r,v,tot,cnt,num[100001],rt[100001];
char ord[3];
int build(int l,int r){
    int u=++tot;
    t[u].lazy=0;
    if(l==r){
        t[u].v=num[l];
        return u;
    }
    int mid=(l+r)/2;
    t[u].ls=build(l,mid);
    t[u].rs=build(mid+1,r);
    t[u].v=t[t[u].ls].v+t[t[u].rs].v;
    return u;
}
int rebuild(int l,int r,int L,int R,int v,int k){
    int u=++tot;
    t[u].v=t[k].v;
    t[u].ls=t[k].ls;
    t[u].rs=t[k].rs;
    t[u].lazy=t[k].lazy;
    if(l==L&&r==R){
        t[u].lazy+=v;
        t[u].v+=v*(r-l+1);
        return u;
    }
    int mid=(l+r)/2;
    if(R<=mid)t[u].ls=rebuild(l,mid,L,R,v,t[k].ls);
    else if(L>mid)t[u].rs=rebuild(mid+1,r,L,R,v,t[k].rs);
    else{
        t[u].ls=rebuild(l,mid,L,mid,v,t[k].ls);
        t[u].rs=rebuild(mid+1,r,mid+1,R,v,t[k].rs);
    }
    t[u].v=t[t[u].ls].v+t[t[u].rs].v;
    t[u].v+=t[u].lazy*(r-l+1);
    return u;
}
ll query(int l,int r,int u,int L,int R){
    if(l==L&&r==R){
        return t[u].v;
    }
    int mid=(l+r)/2;
    ll ans=0;
    if(L>=l&&R<=r)ans+=t[u].lazy*(R-L+1);
    else if(L=l&&R<=r)ans+=t[u].lazy*(R-l+1);
    else if(R>r&&L>=l&&L<=r)ans+=t[u].lazy*(r-L+1);
    else if(Lr)ans+=t[u].lazy*(r-l+1);
    if(R<=mid)ans+=query(l,mid,t[u].ls,L,R);
    else if(L>mid)ans+=query(mid+1,r,t[u].rs,L,R);
    else ans+=query(l,mid,t[u].ls,L,mid)+query(mid+1,r,t[u].rs,mid+1,R);
    return ans;
}
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        tot=cnt=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
        }
        rt[0]=build(1,n);
        for(int i=1;i<=m;i++){
            scanf("%s",ord);
            if(ord[0]=='C'){
                scanf("%d%d%d",&l,&r,&v);
                rt[cnt+1]=rebuild(1,n,l,r,v,rt[cnt]);
                cnt++;
            }else if(ord[0]=='Q'){
                scanf("%d%d",&l,&r);
                printf("%lld\n",query(1,n,rt[cnt],l,r));
            }else if(ord[0]=='H'){
                scanf("%d%d%d",&l,&r,&v);
                printf("%lld\n",query(1,n,rt[v],l,r));
            }else{
                scanf("%d",&v);
                cnt=v;
            }
        }
    }
    return 0;
}

主席树求区间k大

//Orz hjt
//其实和可持久化线段是还是有点区别的QAQ 
#include
#include
#include
#include
#include
using namespace std;
struct node{
    int ls,rs,v;
}t[2000001];
int n,q,k,l,r,pos,tot=0,cnt=0,a[100001],b[100001],rt[100001];
int build(int l,int r){
    int u=++tot;
    t[u].v=0;
    if(l==r)return u;
    int mid=(l+r)/2;
    t[u].ls=build(l,mid);
    t[u].rs=build(mid+1,r);
    return u;
}
int ins(int l,int r,int k,int p){
    int u=++tot;
    t[u].ls=t[k].ls;
    t[u].rs=t[k].rs;
    t[u].v=t[k].v+1;
    if(l==r)return u;
    int mid=(l+r)/2;
    if(p<=mid)t[u].ls=ins(l,mid,t[k].ls,p);
    else t[u].rs=ins(mid+1,r,t[k].rs,p);
    return u;
}
int query(int l,int r,int pre,int now,int k){
    if(t[now].ls==t[now].rs){
        return b[l];
    }
    int mid=(l+r)/2,tmp=t[t[now].ls].v-t[t[pre].ls].v;
    if(tmp>=k)return query(l,mid,t[pre].ls,t[now].ls,k);
    else return query(mid+1,r,t[pre].rs,t[now].rs,k-tmp);
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    rt[0]=build(1,n);
    //printf("a\n");
    for(int i=1;i<=n;i++)rt[i]=ins(1,n,rt[i-1],lower_bound(b+1,b+n+1,a[i])-b);
    for(int i=1;i<=q;i++){
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",query(1,n,rt[l-1],rt[r],k));
    }
    return 0;
}

带修改区间k大(主席树套树状数组)


你可能感兴趣的:(算法-数据结构)