1. 程式人生 > >BZOJ1901:Zju2112 Dynamic Rankings——題解

BZOJ1901:Zju2112 Dynamic Rankings——題解

復雜度 方便 .com ranking www. 查詢 給定 強行 函數

http://www.lydsy.com/JudgeOnline/problem.php?id=1901

Description

給定一個含有n個數的序列a[1],a[2],a[3]……a[n],程序必須回答這樣的詢問:對於給定的i,j,k,在a[i],a[i+1 ],a[i+2]……a[j]中第k小的數是多少(1≤k≤j-i+1),並且,你可以改變一些a[i]的值,改變後,程序還能針對改 變後的a繼續回答上面的問題。

Input

第一行有兩個正整數n(1≤n≤10000),m(1≤m≤10000)。 分別表示序列的長度和指令的個數。 第二行有n個數,表示a[1],a[2]……a[n],這些數都小於10^9。 接下來的m行描述每條指令 每行的格式是下面兩種格式中的一種。 Q i j k 或者 C i t Q i j k (i,j,k是數字,1≤i≤j≤n, 1≤k≤j-i+1) 表示詢問指令,詢問a[i],a[i+1]……a[j]中第k小的數。 C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改變成為t m,n≤10000

Output

對於每一次詢問,你都需要輸出他的答案,每一個輸出占單獨的一行。

Sample Input

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3

Sample Output

3
6

————————————————————————————

帶修改主席樹板子題目(bzoj真喜歡權限板子題)

然後我學了一上午:https://www.cnblogs.com/candy99/p/6166467.html

總的來說如果我們暴力修改主席樹的話,我們對於每一棵主席樹都需要進行修改,那麽這樣時間復雜度就爆棚了。

而我們考慮,樹狀數組和線段樹的修改僅僅只是logn的。

所以我們試著讓樹狀數組套上主席樹,這樣就能方便的修改值了。

也就是說,樹狀數組的每一個節點都掛著一棵主席樹,這樣所需要修改的主席樹就變成O(logn)棵了。

那麽查詢也很簡單,就是樹狀數組的查詢方法(因為我們外層包的是樹狀數組,所以查詢就是在查主席樹的根,也就不需要主席樹了)。

顯然空間復雜度為O(nlognlogn)

!但是!我學的那篇博客提供了一種O(2nlogn)的做法。

我們直接將修改操作另開一棵樹狀數組(貌似樹狀數組節點還套了個線段樹?我不是很懂啊)維護,這樣就變成了主席樹+樹狀數組了,查詢的時候兩者的和一加即可。

註意事項:

1.第二種做法主席樹和樹狀數組的插入方法是不一樣的,為了減少碼量強行壓成了一個函數,所以二者的意義是不一樣的。

2.空間記得根據空間復雜度開。

3.不要用什麽玄學的stl,不然AC變TLE就是一瞬間的事情。

4.離散化。

5.我們既然決定要將樹狀數組和主席樹分來,那麽根節點就不能公用(這也是復雜度多了個2的原因)。

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int N=20010;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==-;ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct tree{
    int l,r,sum;
}tr[N*100];
struct question{
    char s[10];
    int i,j,k,t;
}q[N];
int a[N],b[N],rt[N],root[N],n,m,Q,pool;
inline void initLSH(){
    sort(b+1,b+m+1);
    m=unique(b+1,b+m+1)-b-1;
    return;
}
inline int LSH(int v){return lower_bound(b+1,b+m+1,v)-b;}
inline int lowbit(int x){return x&-x;}
inline void insert(int &x,int l,int r,int p,int v){
    tr[++pool]=tr[x];x=pool;
    tr[x].sum+=v;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(p<=mid)insert(tr[x].l,l,mid,p,v);
    else insert(tr[x].r,mid+1,r,p,v);
    return;
}
void add(int pos,int v){
    int k=LSH(a[pos]);
    for(int i=pos;i<=n;i+=lowbit(i))insert(root[i],1,m,k,v);
    return;
}
int q1[N],t1,q2[N],t2;
inline int cal(){
    int sum1=0,sum2=0;
    for(int i=1;i<=t1;i++)sum1+=tr[tr[q1[i]].l].sum;
    for(int i=1;i<=t2;i++)sum2+=tr[tr[q2[i]].l].sum;
    return sum2-sum1;
}
inline int query(int nl,int nr,int k){
    int l=1,r=m;t1=t2=0;
    for(int i=nl;i;i-=lowbit(i))q1[++t1]=root[i];
    for(int i=nr;i;i-=lowbit(i))q2[++t2]=root[i];
    nl=rt[nl];nr=rt[nr];
    while(l<r){
    int ls=cal()+tr[tr[nr].l].sum-tr[tr[nl].l].sum,mid=(l+r)>>1;
    if(k<=ls){
        for(int i=1;i<=t1;i++)q1[i]=tr[q1[i]].l;
        for(int i=1;i<=t2;i++)q2[i]=tr[q2[i]].l;
        nl=tr[nl].l;nr=tr[nr].l;
        r=mid;
    }else{
        for(int i=1;i<=t1;i++)q1[i]=tr[q1[i]].r;
        for(int i=1;i<=t2;i++)q2[i]=tr[q2[i]].r;
            nl=tr[nl].r;nr=tr[nr].r;
            l=mid+1;k-=ls;
        }
    }
    return l;
}
int main(){
    n=read();
    Q=read();
    for(int i=1;i<=n;i++)a[i]=b[++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].i=read();
        q[i].t=b[++m]=read();
    }
    }
    initLSH();
    for(int i=1;i<=n;i++)rt[i]=rt[i-1],insert(rt[i],1,m,LSH(a[i]),1);
    for(int i=1;i<=Q;i++){
    if(q[i].s[0]==Q)
        printf("%d\n",b[query(q[i].i-1,q[i].j,q[i].k)]);
    else{
        add(q[i].i,-1);
        a[q[i].i]=q[i].t;
        add(q[i].i,1);
    }
    }
    return 0;
}

BZOJ1901:Zju2112 Dynamic Rankings——題解