zoukankan      html  css  js  c++  java
  • 带修改的主席树

    对于单点修改的主席树,我们可以采用树套树来写,原因 不会整体二分求带修改的区间第k小。

    所以学习了一波 待修改的主席树。真的是难写,或者说码量有点大。

    不过和三维偏序CDQ分治相比其实差不了多少,但是CDQ终究比树套树快而且空间消耗小。

    两者都很不错!

    经典题,但是对于我这个根本不懂树套树的人来说是有点难度的考虑整体二分吧,但是呢不会。

    所以上主席树,核心:主席树维护区间 树状数组维护位置。

    还不懂么?先想如果直接线段树的话 每次修改后面的主席树都要改一遍然后 复杂度 n^2logn

    如何优化 考虑树状数组吧 每次修改我们至多修改 logn棵主席树 每棵主席树的修改是 logn的。

    复杂度 log^2n 所以我们愉快的以总时间复杂度 nlog^2n 空间复杂度 (n+m)logn

    都还行。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cctype>
    #include<utility>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<ctime>
    #include<set>
    #include<bitset>
    #include<map>
    #include<cmath>
    #include<vector>
    #include<cstdlib>
    #define INF 2147483646
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;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;
    }
    void put(int x)
    {
        x<0?putchar('-'),x=-x:0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar(10);return;
    }
    const int MAXN=100002;
    struct wy
    {
        int l,r;
        int v;
    }t[60000000];
    struct wy1
    {
        int l,r,k;
    }g[MAXN<<1];
    int n,m;
    int a[MAXN<<1],b[MAXN<<1],cnt,num;
    int root[MAXN<<1],cnt1,ans;
    int q[MAXN],q1[MAXN],top,top1;
    char ch[5];
    void discrete()
    {
        sort(b+1,b+1+cnt);
        for(int i=1;i<=cnt;i++)if(i==1||b[i]!=b[i-1])b[++num]=b[i];
        for(int i=1;i<=cnt;i++)a[i]=lower_bound(b+1,b+1+num,a[i])-b;
    }
    void change(int &now,int l,int r,int w,int x,int d)
    {
        now=++cnt1;t[now]=t[w];
        t[now].v+=d;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(x<=mid)change(t[now].l,l,mid,t[w].l,x,d);
        else change(t[now].r,mid+1,r,t[w].r,x,d);
    }
    void add(int x,int y,int v)
    {
        for(;x<=n;x+=x&(-x))change(root[x],1,num,root[x],v,y);
    }
    int sigma()
    {
        int s=0,s1=0;
        for(int i=1;i<=top1;i++)s1+=t[t[q1[i]].l].v;
        for(int i=1;i<=top;i++)s+=t[t[q[i]].l].v;
        return s-s1;
    }
    void ask(int x,int y,int l,int r,int k)
    {
        top=top1=0;    
        for(;x;x-=x&(-x))q1[++top1]=root[x];
        for(;y;y-=y&(-y))q[++top]=root[y];
        while(l<r)
        {
            int mid=(l+r)>>1;
            int sum=sigma();
            if(sum>=k)
            {
                for(int i=1;i<=top1;i++)q1[i]=t[q1[i]].l;
                for(int i=1;i<=top;i++)q[i]=t[q[i]].l;
                r=mid;
            }
            else
            {
                for(int i=1;i<=top1;i++)q1[i]=t[q1[i]].r;
                for(int i=1;i<=top;i++)q[i]=t[q[i]].r;
                k-=sum;l=mid+1;
            }
        }
        ans=l;return;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();cnt=n;
        for(int i=1;i<=n;i++)a[i]=b[i]=read();
        for(int i=1;i<=m;i++)
        {
            scanf("%s",&ch);
            ++cnt;
            if(ch[0]=='Q')
            {
                g[i].l=read();
                g[i].r=read();
                g[i].k=read();
                b[cnt]=INF;
                a[cnt]=INF;
            }
            else
            {
                g[i].l=read();
                g[i].r=read();
                a[cnt]=g[i].r;
                b[cnt]=g[i].r;
            }
        }
        discrete();
        //for(int i=1;i<=n;i++)cout<<a[i]<<' ';puts("");
        //for(int i=1;i<=n;i++)cout<<b[a[i]]<<' ';puts("");
        for(int i=1;i<=n;i++)add(i,1,a[i]);
        for(int i=1;i<=m;i++)
        {
            if(g[i].k)
            {
                ask(g[i].l-1,g[i].r,1,num,g[i].k);
                put(b[ans]);
            }
            else 
            {
                add(g[i].l,-1,a[g[i].l]);
                //cout<<g[i].l<<endl;
                //cout<<a[g[i].l]<<' '<<b[a[g[i].l]]<<endl;
                add(g[i].l,1,a[i+n]);
                a[g[i].l]=a[i+n];
                //cout<<a[g[i].l]<<' '<<b[a[g[i].l]]<<endl;
            }
        }
        return 0;
    }
    View Code

    我是觉得有点难写了,但是仍然是坚持码完了。

    这道题呢其实也是可以树套树的,考虑先将整体逆序对全部求出然后 每次动态的删除某个数(log^2n)

    然后计算删掉这个数后对答案的总影响即可。

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cctype>
    #include<utility>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<ctime>
    #include<set>
    #include<bitset>
    #include<map>
    #include<cmath>
    #include<vector>
    #include<cstdlib>
    #define INF 2147483646
    #define ll long long
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;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;
    }
    void put(ll x)
    {
        x<0?putchar('-'),x=-x:0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int MAXN=100002;
    int n,m,cnt;
    ll ans;
    int a[MAXN],c[MAXN];
    int root[MAXN<<1],pos[MAXN];
    int q[50],q1[50],top,top1;
    struct wy
    {
        int l,r,v;
    }t[28900000];//空间 nlog^2n 3e7左右 貌似300多MB但是应该能过
    void add(int x,int y){for(;x<=n;x+=x&(-x))c[x]+=y;}
    int ask(int x)
    {
        int cnt=0;
        for(;x;x-=x&(-x))cnt+=c[x];
        return cnt;
    }
    void state()
    {
        for(int i=n;i>=1;i--)
        {
            ans+=ask(a[i]-1);
            add(a[i],1);
        }
        return;
    }
    void change(int &now,int l,int r,int now1,int x,int y)
    {
        if(now==0)now=++cnt;
        t[now]=t[now1];
        t[now].v+=y;
        if(l==r)return;
        int mid=(l+r)>>1;
        if(x<=mid)change(t[now].l,l,mid,t[now1].l,x,y);
        else change(t[now].r,mid+1,r,t[now1].r,x,y);
    }
    void insert(int x,int y)
    {
        for(int i=x;i<=n;i+=i&(-i))
            change(root[i],1,n,root[i],a[x],y);
    }
    int ask(int x,int y,int d,int p)
    {
        top=top1=0;
        for(int i=x-1;i;i-=i&(-i))q[++top]=root[i];
        for(int i=y;i;i-=i&(-i))q1[++top1]=root[i];
        int l=1,r=n,num=0,num1=0,num2=0;
        while(l!=r)
        {
            int mid=(l+r)>>1;
            if(d>mid)
            {
                if(p==0) //询问当前有多少数字比d小
                {
                    num1=0,num2=0;
                    for(int i=1;i<=top;i++)num2+=t[t[q[i]].l].v;
                    for(int i=1;i<=top1;i++)num1+=t[t[q1[i]].l].v;
                    num+=num1-num2;
                }
                for(int i=1;i<=top;i++)q[i]=t[q[i]].r;
                for(int i=1;i<=top1;i++)q1[i]=t[q1[i]].r;
                l=mid+1;
            }
            else
            {
                if(p==1)
                {
                    num1=0,num2=0;
                    for(int i=1;i<=top;i++)num2+=t[t[q[i]].r].v;
                    for(int i=1;i<=top1;i++)num1+=t[t[q1[i]].r].v;
                    num+=num1-num2;
                }
                for(int i=1;i<=top;i++)q[i]=t[q[i]].l;
                for(int i=1;i<=top1;i++)q1[i]=t[q1[i]].l;
                r=mid;
            }
        }
        return num;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=n;i++)a[i]=read(),pos[a[i]]=i;
        state();
        for(int i=1;i<=n;i++)insert(i,1);
        for(int i=1;i<=m;i++)
        {
            put(ans);
            int x=read();
            insert(pos[x],-1);
            ans-=ask(1,pos[x]-1,x,1);
            ans-=ask(pos[x]+1,n,x,0);
        }
        return 0;
    }
    View Code

    我也不知道还能坚持多久。

  • 相关阅读:
    Jenkins pipeline基本结构
    接口测试框架httprunner使用自定义extentreports报告模板遇到的问题小结
    python3中扩展字典类实现用点访问属性
    python3系列五可迭代对象、迭代器和生成器
    vue.js-组件嵌套
    使用Vue-CLI3.x进行vue.js环境搭建
    python系列四反射机制
    vue.js环境搭建踩坑记
    python系列三推导式
    python系列二filter()、map()和reduce()
  • 原文地址:https://www.cnblogs.com/chdy/p/10450964.html
Copyright © 2011-2022 走看看