[BZOJ 1901] Dynamic Rankings

Link:

BZOJ 1901 传送门

Solution:

带修改主席树的模板题

对于静态区间第$k$大直接上主席树就行了

但加上修改后会发现修改时复杂度不满足要求了:

去掉/增加第$i$位上的值时要更新$i...n$间所有的主席树,使得单次修改的复杂度达到$n*log(n)$

 

可以将原来的主席树看成前缀数组

求某一段时尚可直接差分,但涉及到修改时就要改动$O(n)$级别的节点了

这时想到优化前缀和问题的树状数组

如果将原来的每一棵主席树看作树状数组上的点并利用$lowbit()$修改/求值

这样就能每次改动$log(n)$棵主席树,从而将复杂度降到$log(n)^2$

 

实现中先离散化,对于每一次修改先去掉删除原值,再添加新值就好啦

注意修改时要先记录所有需要的节点并一起移动,对于$k$大问题无法单独计算

 

Tip:

1、此时每棵线段树已经不再具有主席树的性质了:每次修改在前者基础上增加一条链

其实现在每棵线段树就是在自己原基础上修改,准确地说就是树状数组套动态开点权值线段树

2、好像此类动态开点线段树的空间复杂度我不太会算……

此题好像$O(n*log(n))$就够用了……

Code:

#include <bits/stdc++.h>

using namespace std;
const int MAXN=10005;
char s[20];
struct Query{int i,j,k;}q[MAXN];
//内存开大,好像这题n*log(n)就够了
struct PrTree{int ls,rs,cnt;}seg[3000005];
int n,m,dat[MAXN],rt[MAXN],L[30],R[30],dsp[MAXN<<1],tot,totl,totr,cnt;
inline int lowbit(int x){return x&(-x);}
//PrTree
void Update(int &cur,int pos,int val,int l,int r)
{
    if(!cur) cur=++cnt;
    seg[cur].cnt+=val;
    if(l==r) return;int mid=(l+r)>>1;
    if(pos<=mid) Update(seg[cur].ls,pos,val,l,mid);
    else Update(seg[cur].rs,pos,val,mid+1,r);
}

int Query(int k,int l,int r)
{
    if(l==r) return l;
    int sum=0,mid=(l+r)>>1;
    for(int i=1;i<=totl;i++) sum-=seg[seg[L[i]].ls].cnt;
    for(int i=1;i<=totr;i++) sum+=seg[seg[R[i]].ls].cnt;
    if(sum>=k)
    {
        for(int i=1;i<=totl;i++) L[i]=seg[L[i]].ls;
        for(int i=1;i<=totr;i++) R[i]=seg[R[i]].ls;
        return Query(k,l,mid);
    }
    else
    {
        for(int i=1;i<=totl;i++) L[i]=seg[L[i]].rs;
        for(int i=1;i<=totr;i++) R[i]=seg[R[i]].rs;
        return Query(k-sum,mid+1,r);
    }
}
//BIT
void upd(int x,int val)
{
    int pos=lower_bound(dsp+1,dsp+tot+1,dat[x])-dsp;
    for(int i=x;i<=n;i+=lowbit(i))
        Update(rt[i],pos,val,1,tot);
}

int qry(int l,int r,int k)
{
    totl=totr=0;
    for(int i=l-1;i;i-=lowbit(i)) L[++totl]=rt[i];
    for(int i=r;i;i-=lowbit(i)) R[++totr]=rt[i];
    return dsp[Query(k,1,tot)];
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&dat[i]),dsp[++tot]=dat[i];
    for(int i=1;i<=m;i++)
    {
        scanf("%s%d%d",s,&q[i].i,&q[i].j);
        if(s[0]=='Q') scanf("%d",&q[i].k);
        else dsp[++tot]=q[i].j;
    }
    sort(dsp+1,dsp+tot+1);
    tot=unique(dsp+1,dsp+tot+1)-dsp-1;
    
    for(int i=1;i<=n;i++) upd(i,1);
    for(int i=1;i<=m;i++)
    {
        if(q[i].k) printf("%d\n",qry(q[i].i,q[i].j,q[i].k));
        else upd(q[i].i,-1),dat[q[i].i]=q[i].j,upd(q[i].i,1);
    }
    return 0;
}

 

posted @ 2018-07-23 22:18  NewErA  阅读(150)  评论(0编辑  收藏  举报