整體二分——帶修改區間第k大
阿新 • • 發佈:2018-12-16
Description
給定一個長度為N的已知序列A[i](1<=i<=N),要求維護這個序列,能夠支援以下兩種操作: 1、查詢A[i],A[i+1],A[i+2],…,A[j](1<=i<=j<=N)中,升序排列後排名第k的數。 2、修改A[i]的值為j。 所謂排名第k,指一些數按照升序排列後,第k位的數。例如序列{6,1,9,6,6},排名第3的數是6,排名第5的數是9。
Input
輸入檔案的第一行包含兩個整數N和M,分別表示序列的長度為N和有M個操作。 接下來的N個不大於10^9正整數,第i個表示序列A[i]的初始值。 然後的M行,每行為一個操作Q i j k 或者C i j分別表示查詢A[i],A[i+1],A[i+2],…,A[j](1<=i<=j<=N)中,升序排列後排名第k的數和修改A[i]的值為j。
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
Hint
【資料範圍】: 20%的資料中,m,n≤100; 40%的資料中,m,n≤1000; 100%的資料中,m,n≤10000。
把修改看成刪除一次插入一次,因為整體二分時自然保證時間連續,我們就可以亂搞。
我們二分答案,對於修改的數k小於等於mid的,修改後歸為左區間,查詢類似。
注意整個操作我們均保證了a[i]的時間在a[i-1]的時間之後,因此修改拆成刪除和插入是可以的,這兩個操作總是一個整體。
#include<bits/stdc++.h> using namespace std; const int Maxn=40005; struct Operator{ int x,k,type;//-1刪除 1新增 0詢問 int L,R,index; }a[Maxn],Left[Maxn],Right[Maxn]; int n,m,cnt,cntq,v[Maxn],ans[Maxn]; struct Tree_Array{ int c[Maxn]; #define lowbit(x) (x)&-(x) void add(int x,int k){ for(;x<=n;x+=lowbit(x))c[x]+=k; } int sum(int x){ int ret=0; for(;x>0;x-=lowbit(x))ret+=c[x]; return ret; } }bit; void Solve(int ql,int qr,int al,int ar){ if(ql>qr)return ; if(al==ar){ for(int i=ql;i<=qr;++i) if(a[i].type==0)ans[a[i].index]=al; return ; } int cntl=0,cntr=0,cnt=ql-1,mid=(al+ar)/2; for(int i=ql;i<=qr;++i){ if(a[i].type){ if(a[i].k<=mid){ bit.add(a[i].x,a[i].type); Left[++cntl]=a[i]; }else { Right[++cntr]=a[i]; } }else { int Rank=bit.sum(a[i].R)-bit.sum(a[i].L-1); if(a[i].k<=Rank){ Left[++cntl]=a[i]; }else { a[i].k-=Rank; Right[++cntr]=a[i]; } } } for(int i=ql;i<=qr;++i) if(a[i].type&&a[i].k<=mid)bit.add(a[i].x,-a[i].type); for(int i=1;i<=cntl;++i)a[++cnt]=Left[i]; for(int i=1;i<=cntr;++i)a[++cnt]=Right[i]; Solve(ql,ql+cntl-1,al,mid),Solve(ql+cntl,qr,mid+1,ar); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ scanf("%d",&v[i]); a[++cnt]=(Operator){i,v[i],1}; } for(int i=1;i<=m;++i){ char c=getchar();while(!isalpha(c))c=getchar(); // cout<<c<<"\n"; if(c=='Q'){ a[++cnt].type=0;a[cnt].index=++cntq; scanf("%d%d%d",&a[cnt].L,&a[cnt].R,&a[cnt].k); }else { int x,k;scanf("%d%d",&x,&k); a[++cnt]=(Operator){x,v[x],-1}; a[++cnt]=(Operator){x,v[x]=k,1}; } } Solve(1,cnt,-(1<<30),(1<<30)); for(int i=1;i<=cntq;++i) cout<<ans[i]<<endl; return 0; }