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;
}