• [bzoj1901][Zju2112]Dynamic Rankings_主席树


    Dynamic Rankings bzoj-1901 Zju-2112

    题目大意:给定一个n个数的序列,m个操作,支持:单点修改;查询区间k小值。

    注释:$1le n,mle 10^4$。


    想法:如果这个教树套树的话,我也没办法。

    其实就是借用了树状数组的思想,我们在这里叫它...阉割树状数组把。

    具体地,主席树每个节点维护的仍然是前缀权值线段树。

    修改的时候将修改的点二进制lowbit分解。在分解的节点的权值线段树上直接修改。

    查询时我们将所有区间(左端点-1)都二进制lowbit分解,然后每个点的sum都在delta上修改,判断进左子树还是右子树即可。

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 100500
    int sum[N<<5],ls[N<<5],rs[N<<5],n,m,root[N<<5];
    int sx[N],sy[N],v[N],maxn=1e9+10,cnt,cntx,cnty;
    char ch[10];
    inline int lowbit(int i){return i&(-i);}
    // int build(int l,int r)
    // {
    // 	int pos=++cnt,mid=(l+r)>>1;
    // 	if(l==r) return pos;
    // 	ls[pos]=build(l,mid);
    // 	rs[pos]=build(mid+1,r);
    // 	return pos;
    // }
    int update(int pre,int l,int r,int k,int val)
    {
    	int pos=++cnt,mid=(l+r)>>1;
    	sum[pos]=sum[pre]+val;
    	ls[pos]=ls[pre]; rs[pos]=rs[pre];
    	if(l==r) return pos;
    	if(k<=mid) ls[pos]=update(ls[pre],l,mid,k,val);
    	else rs[pos]=update(rs[pre],mid+1,r,k,val);
    	return pos;
    }
    int query(int l,int r,int k)
    {
        if(l==r) return l;
        int dlt=0,mid=(l+r)>>1;
        for(int i=1;i<=cntx;i++) dlt-=sum[ls[sx[i]]];
        for(int i=1;i<=cnty;i++) dlt+=sum[ls[sy[i]]];
        if(k<=dlt)
    	{
            for(int i=1;i<=cntx;i++) sx[i]=ls[sx[i]];
            for(int i=1;i<=cnty;i++) sy[i]=ls[sy[i]];
            return query(l,mid,k);
        }
    	else
    	{
            for(int i=1;i<=cntx;i++) sx[i]=rs[sx[i]];
            for(int i=1;i<=cnty;i++) sy[i]=rs[sy[i]];
            return query(mid+1,r,k-dlt);
        }
    }
    int main()
    {
        int x,y,z;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&v[i]);
    		for(int j=i;j<=(n<<1);j+=lowbit(j)) root[j]=update(root[j],0,maxn,v[i],1);
    	}
        for(int i=1;i<=m;i++)
    	{
            scanf("%s%d%d",ch,&x,&y);
            if(ch[0]=='C')
    		{
                for(int j=x;j<=n;j+=lowbit(j)) root[j]=update(root[j],0,maxn,v[x],-1);
                v[x]=y;
                for(int j=x;j<=n;j+=lowbit(j)) root[j]=update(root[j],0,maxn,v[x],1);
            }
    		else
    		{
                scanf("%d",&z);
    			cntx=cnty=0;
                for(int j=x-1;j;j-=lowbit(j)) sx[++cntx]=root[j];
                for(int j=y;j;j-=lowbit(j)) sy[++cnty]=root[j];
                printf("%d
    ",query(0,maxn,z));
            }
        }
    }
    /*
    5 3
    
    3 2 1 4 7
    
    Q 1 4 3
    
    C 2 6
    
    Q 2 5 3
    */
    

    小结:有趣...

  • 相关阅读:
    java的hashcode和equals
    Spring 注入所得
    Action注入错误
    oracle中的替换函数replace和translate函数
    CSS div水平垂直居中和div置于底部
    java double类型保留两位小数4种方法
    Delphi写的DLL回调C#
    Java基础进阶整理
    j技术方案
    SetForegroundWindow激活窗口
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9393321.html
Copyright © 2020-2023  润新知