[bzoj1901][Zju2112]Dynamic Rankings_主席树

Dynamic Rankings bzoj-1901 Zju-2112

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

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


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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#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\n",query(0,maxn,z));
        }
    }
}
/*
5 3
 
3 2 1 4 7
 
Q 1 4 3
 
C 2 6
 
Q 2 5 3
*/

小结:有趣...

posted @   JZYshuraK_彧  阅读(187)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示