• 主席树模板(区间第k小+可持久化数组+带回溯线段树)


    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 200010
    using namespace std;
    int n,m,cnt;
    struct Tree
    {
        int l,r,sum;
    }T[MAXN*60];
    int rank[MAXN],root[MAXN];
    struct data
    {
        int val,ind;
        bool operator < (const data &a) const
        {
            return val<a.val;
        }
    }a[MAXN];
    void insert(int &num,int &x,int l,int r)
    {
        T[cnt++]=T[x];
        x=cnt-1;
        T[x].sum++;
        if(l==r) return;
        int mid=(l+r)/2;
        if(num<=mid) insert(num,T[x].l,l,mid);
        else insert(num,T[x].r,mid+1,r);
    }
    int query(int i,int j,int k,int l,int r)
    {
        if(l==r) return l;
        int t=T[T[j].l].sum-T[T[i].l].sum;
        int mid=(r+l)/2;
        if(k<=t) return query(T[i].l,T[j].l,k,l,mid);
        else return query(T[i].r,T[j].r,k-t,mid+1,r);
    }
    int main()
    {
        T[0].l=T[0].r=T[0].sum=root[0]=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i].val);
            a[i].ind=i;
        }
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++)
        {
            rank[a[i].ind]=i;
        }
        cnt=1;
        for(int i=1;i<=n;i++)
        {
            root[i]=root[i-1];
            insert(rank[i],root[i],1,n);
        }
        while(m--)
        {
            int i,j,k;
            scanf("%d%d%d",&i,&j,&k);
            printf("%d
    ",a[query(root[i-1],root[j],k,1,n)].val);
        }
    }
     
    区间第K小

    第K小没什么说的(其实是我还不太会)

    下面是可持久化数组的代码

    题目大意:对于一个数组,修改一个值或查询某版本下某位的值(查询也算一个版本)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    struct Tree
    {
        int ls,rs;
        int val;
    }T[1000010*60];
    int cnt;
    int a[1000010];
    int root[1000010];
    void build(int l,int r)
    {
         if(l==r) {T[++cnt].val=a[l];return;}
         int mid=(l+r)/2;
         build(l,mid);
         int l1=cnt;
         build(mid+1,r);
         int r1=cnt;
         T[++cnt].ls=l1;T[cnt].rs=r1;
    }
    /*void check(int x,int l,int r)
    {
        if(l>r) return;
        if(l==r) {printf("%d ",T[x].val);return;}
        int mid=(l+r)/2;
        check(T[x].ls,l,mid);
        check(T[x].rs,mid+1,r);
        return;
    }这里是判断建树是否正确*/
    void ask(int p,int x,int l,int r)
    {
        if(l>r) return;
        if(l==r) {printf("%d
    ",T[p].val);return;}
        int mid=(l+r)/2;
        if(x>mid) ask(T[p].rs,x,mid+1,r);
        else ask(T[p].ls,x,l,mid);
    }
    void change(int p,int x,int y,int l,int r)
    {
        if(l>r) return;
        T[++cnt]=T[p];
        if(l==r) {T[cnt].val=y;return;}
        int mid=(l+r)/2;
        if(x>mid) {T[cnt].rs=cnt+1;change(T[p].rs,x,y,mid+1,r);}
        else {T[cnt].ls=cnt+1;change(T[p].ls,x,y,l,mid);}
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,n);
        root[0]=cnt;
        for(int i=1;i<=m;i++)
        {
            root[i]=cnt+1;
            int a,b;
            scanf("%d%d",&a,&b);
            if(b==1)
            {
                int c,d;
                scanf("%d%d",&c,&d);
                change(root[a],c,d,1,n);
            }
            else
            {
                cnt++;
                int c;
                scanf("%d",&c);
                T[root[i]]=T[root[a]];
                ask(root[i],c,1,n);
            }
        }
    }
    可持久化数组

     带回溯线段树

    回溯是指当前版本与k前相同(两次回溯一个版本相当于不回溯,但版本号加了二,再变成上一个版本需要回溯3个版本)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    struct node
    {
        int l,r,ls,rs;
        int val,tag;
    }T[60*250010];
    int A[100010];
    int root[100010];
    int cnt=0,n,m;
    void build(int l,int r)
    {
        if(l==r) {T[++cnt].val=A[l];T[cnt].l=l;T[cnt].r=r;return;}
        int mid=(l+r)/2,tmp;
        build(l,mid);
        tmp=cnt;
        build(mid+1,r);
        T[++cnt].ls=tmp;
        T[cnt].rs=cnt-1;
        T[cnt].l=l;T[cnt].r=r;
        T[cnt].val=T[cnt-1].val+T[tmp].val;
    }
    void pushdown(int id)
    {
        if(id)
        {
            T[T[id].ls].tag+=T[id].tag;
            T[T[id].rs].tag+=T[id].tag;
            T[id].val=T[T[id].ls].tag*(T[T[id].ls].r-T[T[id].ls].l)+T[T[id].ls].val;
            T[id].val+=T[T[id].rs].tag*(T[T[id].rs].r-T[T[id].rs].l)+T[T[id].rs].val;
            T[id].tag=0;
        }
        return;
    }
    void change(int id,int v,int l,int r)
    {
        T[++cnt]=T[id];
        if(T[cnt].r==r&&T[cnt].l==l) {T[cnt].tag+=v;return;}
        pushdown(cnt);
        int tmp=cnt;
        int mid=(T[id].l+T[id].r)/2;
        if(mid>=l) {T[tmp].ls=cnt+1;change(T[id].ls,v,l,min(mid,r));}
        if(mid<r) {T[tmp].rs=cnt+1;change(T[id].rs,v,max(mid+1,l),r);}
        return;  
    }
    int query(int id,int l,int r)
    {
        if(T[id].r==r&&T[id].l==l) return T[id].val+T[id].tag*(r-l+1);
        pushdown(id);
        int tmp=0,mid=(T[id].l+T[id].r)/2;
        if(mid>=l) tmp+=query(T[id].ls,l,min(mid,r));
        if(mid<r) tmp+=query(T[id].rs,max(mid+1,l),r);
        return tmp;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&A[i]);
        }
        build(1,n);
        root[0]=cnt;
        int num=0;
        for(int i=1;i<=m;i++)
        {
            int opt;
            scanf("%d",&opt);
            if(opt==1)//区间加
            {
                root[++num]=cnt+1;
                int v,l,r;scanf("%d%d%d",&l,&r,&v);
                change(root[num-1],v,l,r);
            }
            if(opt==2)//区间查询
            {
                int l,r;scanf("%d%d",&l,&r);
                printf("%d
    ",query(root[num],l,r));
            } 
            if(opt==3)//回溯 
            {
                int k;
                scanf("%d
    ",&k);
                root[++num]=cnt+1;
                T[++cnt]=T[root[max(0,num-1-k)]];
            }
        }
    }
    带回溯线段树
  • 相关阅读:
    下载vue-devtools插件的步骤
    弄清 CSS3 的 transition 和 animation
    js与多行字符串
    swift 上手
    liunux 修改hostname
    linux 下使用配置文件
    linux安装oracle11g
    jQueryt过滤选择器
    Javascript并发模型和事件循环
    CSS生僻问题一网打尽
  • 原文地址:https://www.cnblogs.com/wjxgy/p/7789327.html
Copyright © 2020-2023  润新知