整体二分学习
意思能懂,解说也都懂,但是为什么这样(查询和修改都弄在一起就能......)还是有些疑问。觉得看到题目知道是整体二分也不好写。
带修改的区间第k小,经典代码。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #define maxn 220000 #define inf 1000000000 using namespace std; struct query { int x,y,k,s,tp,cur; } q[maxn],q1[maxn],q2[maxn]; int a[maxn],ans[maxn],tmp[maxn],t[maxn]; int n,m,num,cnt; void add(int x,int y) { for (int i=x; i<=n; i+=(i&-i)) t[i]+=y; } int ask(int x) { int tmp=0; for (int i=x; i>0; i-=(i&-i)) tmp+=t[i]; return tmp; } void divide(int head,int tail,int l,int r) { //cout<<head<<' '<<tail<<' '<<l<<' '<<r<<endl; if (head>tail) return ; if (l==r) { for (int i=head; i<=tail; i++) if (q[i].tp==3) ans[q[i].s]=l;//,cout<<l<<endl; return ; } int mid=(l+r)>>1; for (int i=head; i<=tail; i++)//区间内小于mid的值的个数 { if (q[i].tp==1&&q[i].y<=mid) add(q[i].x,1); else if (q[i].tp==2&&q[i].y<=mid) add(q[i].x,-1); else if (q[i].tp==3) tmp[i]=ask(q[i].y)-ask(q[i].x-1); } for (int i=head; i<=tail; i++)//还原 { if (q[i].tp==1&&q[i].y<=mid) add(q[i].x,-1); else if (q[i].tp==2&&q[i].y<=mid) add(q[i].x,1); } int l1=0,l2=0; for (int i=head; i<=tail; i++) { if (q[i].tp==3)//查询 { if (q[i].cur+tmp[i]>q[i].k-1)//q[i].cur+tmp[i]表示累积了多少个数(之前的+这次的),超限了,就不能加了 q1[++l1]=q[i]; else//加上这轮的,小于k的数还不够 { q[i].cur+=tmp[i];//现在有多少小的了 q2[++l2]=q[i]; } } else { if (q[i].y<=mid) q1[++l1]=q[i];//不够进q1 else q2[++l2]=q[i]; } } for (int i=1; i<=l1; i++) q[head+i-1]=q1[i]; for (int i=1; i<=l2; i++) q[head+l1+i-1]=q2[i]; divide(head,head+l1-1,l,mid); divide(head+l1,tail,mid+1,r); } int main() { //freopen("ranking.in","r",stdin); //freopen("ranking.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) { scanf("%d",&a[i]); q[++num].x=i; q[num].y=a[i]; q[num].tp=1; q[num].s=0; } char sign; int x,y,z; for (int i=1; i<=m; i++) { scanf("\n%c",&sign); if (sign=='Q') { scanf("%d%d%d",&x,&y,&z); q[++num].x=x; q[num].y=y; q[num].k=z; q[num].tp=3; q[num].s=++cnt; } else { scanf("%d%d",&x,&y); q[++num].x=x; q[num].y=a[x]; q[num].tp=2; q[num].s=0; q[++num].x=x; q[num].y=y; q[num].tp=1; q[num].s=0; a[x]=y; } } divide(1,num,0,inf); for (int i=1; i<=cnt; i++) printf("%d\n",ans[i]); return 0; }