P2617 Dynamic Rankings

P2617 Dynamic Rankings

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繼續回答上面的問題。你需要編一個這樣的程序,從輸入文件中讀入序列a,然後讀入一系列的指令,包括詢問指令和修改指令。

    對於每一個詢問指令,你必須輸出正確的回答。

Input

  • 第一行有兩個正整數n(1≤n≤100000),m(1≤m≤100000)。分別表示序列的長度和指令的個數。

    第二行有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。

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

Data Size

  • 10%的數據中,m,n≤100;

    20%的數據中,m,n≤1000;

    50%的數據中,m,n≤10000。

    對於所有數據,m,n≤100000

題解:

  • 樹套樹。
  • ... ...有點難
  • 首先沒有修改就是個裸奔的主席樹。有修改的話假設修改位置爲pos,那麼編號爲pos~n的主席樹都要進行修改。最壞情況O(n^2*logn)。

  • 樹狀數組是個神奇的玩意,現有一題單點修改,區間查詢和的題。每次修改操作樹狀數組只需修改logn個點。
  • 那?把樹狀數組套上主席樹試試?
  • 沒錯,就是那麼暴力。
  • 套上就是指將原先樹狀數組的每個點換成一棵主席樹。每次修改logn棵主席樹。查詢時對logn棵主席樹操作(新樹信息由logn棵主席樹得到)。
  • 套上去了... ...套上去了... ...
  • 是不是感覺超暴力的但又特別妙?
  • 時間複雜度O(n*(logn)^2)。空間複雜度O(我不知道,玄學,有dalao知道務必告訴我)

#include <iostream>
#include <cstdio>
#include <algorithm>
#define lowbit(x) (x&(-x))
#define find(x) (lower_bound(b+1,b+1+cnt,x)-b)
#define N 100005
using namespace std;

struct T {int l,r,sum;}t[N*32*10];
struct Q {int l,r,k;}q[N];
int n,m,cnt,dex,cnt1,cnt2;
int a[N],b[N*10],rt[N],h1[N],h2[N];

int read()
{
    int x=0,f=1;char c=getchar();
    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 build(int l,int r)
{
    int p=++dex,mid=l+r>>1;
    if(l==r) return p;
    t[p].l=build(l,mid);
    t[p].r=build(mid+1,r);
    return p;
}

void upd(int &lat,int l,int r,int pos,int val)
{
    if(!lat) lat=++dex;
    t[lat].sum+=val;
    if(l==r) return;
    int mid=l+r>>1;
    if(pos<=mid) upd(t[lat].l,l,mid,pos,val);
    else upd(t[lat].r,mid+1,r,pos,val);
}

void Upd(int pos,int val)
{
    int poss=find(a[pos]);
    for(int i=pos;i<=n;i+=lowbit(i))
        upd(rt[i],1,cnt,poss,val);
}

int ask(int l,int r,int rank)
{
    int size=0,mid=l+r>>1;
    for(int i=1;i<=cnt2;i++) size+=t[t[h2[i]].l].sum;
    for(int i=1;i<=cnt1;i++) size-=t[t[h1[i]].l].sum;
    if(l==r) return l;
    if(rank<=size) {
        for(int i=1;i<=cnt2;i++) h2[i]=t[h2[i]].l;
        for(int i=1;i<=cnt1;i++) h1[i]=t[h1[i]].l;
        return ask(l,mid,rank);
    }
    else {
        for(int i=1;i<=cnt2;i++) h2[i]=t[h2[i]].r;
        for(int i=1;i<=cnt1;i++) h1[i]=t[h1[i]].r;
        return ask(mid+1,r,rank-size);
    }
}

int Ask(int l,int r,int k)
{
    cnt1=cnt2=0;
    for(int i=l-1;i>=1;i-=lowbit(i)) h1[++cnt1]=rt[i];
    for(int i=r;i>=1;i-=lowbit(i)) h2[++cnt2]=rt[i];
    return b[ask(1,cnt,k)];
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        a[i]=b[++cnt]=read();
    for(int i=1;i<=m;i++) {
        char c[3]; scanf("%s",c);
        if(c[0]=='Q') q[i].l=read(),q[i].r=read(),q[i].k=read();
        else q[i].l=read(),q[i].r=read(),b[++cnt]=q[i].r;
    }
    sort(b+1,b+1+cnt);
    cnt=unique(b+1,b+1+cnt)-b-1;
    rt[0]=build(1,cnt);
    for(int i=1;i<=n;i++) Upd(i,1);
    for(int i=1;i<=m;i++) {
        if(!q[i].k) {
            Upd(q[i].l,-1);
            a[q[i].l]=q[i].r;
            Upd(q[i].l,1);
        }
        else printf("%d\n",Ask(q[i].l,q[i].r,q[i].k));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章