• zoj2112&&bzoj1901


    题解:

    可修改的主席树

    一开始,我就按照最暴力的方法,空间nlognlogn

    然后zju上面过不了,bzoj没有权限号

    然后,参考了往上的论文,发现可以把初始的主席树先建好

    然后,每次只需要维护修改的就可以了

    而且修改的内容只有2个数字

    可以快那么一些

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ls(x) t[x].lc
    #define rs(x) t[x].rc
    typedef long long ll;
    const int N=50005;
    int read()
    {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    int q1[N],t1,q2[N],t2,sz=0,root[N],rt[N],n,Q,m,a[N],mp[N*2],i,j,k;
    char s[2];
    struct question
    {
        char s[3];
        int i,j,k,x,d;
    }q[N];
    struct node
    {
        int lc,rc,w;
    }t[N*50];
    int Bin(int v)
    {
        int l=1,r=m;
        while (l<=r)
         {
            int mid=(l+r)>>1;
            if(mp[mid]==v) return mid;
            if(mp[mid]>v) r=mid-1;
            else l=mid+1;
         }
        return -1;
    }
    void ins(int &x,int l,int r,int num,int v)
    {
        t[++sz]=t[x];x=sz;
        t[x].w+=v;
        if(l==r) return;
        int mid=(l+r)>>1;
        if (num<=mid) ins(t[x].lc,l,mid,num,v);
        else ins(t[x].rc,mid+1,r,num,v);
    }
    void add(int p,int v)
    {
        int xx=Bin(a[p]);
        for (int i=p;i<=n;i+=i&-i) ins(root[i],1,m,xx,v);
    }
    int cal()
    {
        int sum1=0,sum2=0;
        for (int i=1;i<=t1;i++) sum1+=t[ls(q1[i])].w;
        for (int i=1;i<=t2;i++) sum2+=t[ls(q2[i])].w;
        return sum2-sum1;
    }
    int query(int ql,int qr,int k)
    {
        int l=1,r=m;t1=t2=0;
        for (int i=ql-1;i;i-=i&-i) q1[++t1]=root[i];
        for (int i=qr;i;i-=i&-i) q2[++t2]=root[i];
        ql--;
        ql=rt[ql];qr=rt[qr];
        while (l<r)
         {
            int lsize=cal()+t[ls(qr)].w-t[ls(ql)].w,mid=(l+r)>>1;
            if (k<=lsize)
             {
                for (int i=1;i<=t1;i++) q1[i]=t[q1[i]].lc;
                for (int i=1;i<=t2;i++) q2[i]=t[q2[i]].lc;
                ql=ls(ql);qr=ls(qr);
                r=mid;
             }
            else
             {
                for (int i=1;i<=t1;i++) q1[i]=t[q1[i]].rc;
                for (int i=1;i<=t2;i++) q2[i]=t[q2[i]].rc;
                ql=rs(ql);qr=rs(qr);
                l=mid+1;k-=lsize;
             } 
         }
        return l;
    }
    int main()
    {
        int T=read();
        while (T--)
         {
             m=sz=0;
             memset(q,0,sizeof q);
             memset(t,0,sizeof t);
             memset(rt,0,sizeof rt);
             memset(root,0,sizeof root);
            n=read();Q=read();
            for (int i=1;i<=n;i++)a[i]=mp[++m]=read();
            for (int i=1;i<=Q;i++)
             {
                scanf("%s",q[i].s);
                if (q[i].s[0]=='Q') q[i].i=read(),q[i].j=read(),q[i].k=read();
                else q[i].x=read(),q[i].d=mp[++m]=read();
             }
            sort(mp+1,mp+1+m);
            int p=1;
            for (int i=2;i<=m;i++) if(mp[i]!=mp[i-1]) mp[++p]=mp[i];
            m=p;
            for (int i=1;i<=n;i++) rt[i]=rt[i-1],ins(rt[i],1,m,Bin(a[i]),1);
                for (int i=1;i<=Q;i++)
             {
                if(q[i].s[0]=='Q')
                 printf("%d
    ",mp[query(q[i].i,q[i].j,q[i].k)]);
                else
                 {
                    add(q[i].x,-1);
                    a[q[i].x]=q[i].d;
                    add(q[i].x,1);
                 }
             }
         }
        return 0;
    }
  • 相关阅读:
    网络最大流算法—最高标号预流推进HLPP
    网络最大流算法—EK算法
    PROPAGATION_REQUIRED
    js左侧三级菜单导航代码
    Ubuntu上用premake编译GDAL
    2013数据结构课程设计之便利店选址(暴力枚举和随机函数两种做法)
    JAVA环境配置
    [K/3Cloud] 如何从被调用的动态表单界面返回数据
    document.getElementsByClassName在ie8及其以下浏览器的兼容性问题
    Java学习笔记51:数组转ArrayList和ArrayList转数组技巧
  • 原文地址:https://www.cnblogs.com/xuanyiming/p/7931102.html
Copyright © 2020-2023  润新知