P2617 Dynamic Rankings
题意:
待修改的区间最值问题
题解:
整体二分天然带有修改性
整体二分做不带修改的区间最值—>看这里
现在待修改,我们可以将第l位修改为x,因为我们是用树状数组来维护的,所以把这个过程拆分成将第l个数删去,再将第l个数加上,但是这两个第l数所指的值是不一样的,因为我们是判断,只有值<=mid的数才插入到树状数组中,虽然是同一个位置,但是因为可能改了值导致原本插入,现在不插入,也有可能相反,这样就实现了修改操作,其实还是要把整体二分的原理搞清楚就懂了
比如:当然mid = 3
第L位原本是2现在改成4
一开始第L位是插入到树状数组的(因为2<mid)(读入数据时的操作),然后先将第L位删去(修改操作分离出的删去操作),然后判断现在值是否满足要求,发现不满足(4>mid=3),则不插入到树状数组,这样一套,就完成了修改
代码:
#pragma optimize("Ofast")
#include<bits/stdc++.h>
#define MAXN 300005
#define inf int(1e9)
using namespace std;
typedef long long ll;int N,M;
int a[MAXN];struct Node{int op,x,y,k;//op=insert+1/remove-1,query2int id;Node(int op=0, int x=0, int y=0, int k=0, int id=0):op(op), x(x), y(y), k(k), id(id){}
} q[MAXN],lq[MAXN],rq[MAXN];//
int fw[MAXN];
inline int lbt(int x){return x&(-x);
}inline void change(int x, int dv){for(;x<=N;x+=lbt(x)){fw[x] += dv;}
}inline int query(int x){int ans = 0;for(;x>0;x-=lbt(x)){ans += fw[x];}return ans;
}
//
int ANS[MAXN];void solve(int vl, int vr, int ql, int qr){//cerr<<"solve: "<<vl<<" "<<vr<<" "<<ql<<" "<<qr<<endl;if(ql > qr) return;if(vl == vr){for(int i=ql;i<=qr;i++){if(q[i].op==2) ANS[q[i].id] = vl;}return;}//insertint mid = (vl + vr)>>1;int nl = 0, nr = 0;for(int i=ql;i<=qr;i++){if(q[i].op != 2){//insert/removeif(q[i].x <= mid) change(q[i].y, q[i].op), lq[++nl] = q[i];else rq[++nr] = q[i];}else{//queryint n = query(q[i].y) - query(q[i].x-1);if(q[i].k <= n) lq[++nl] = q[i];else{q[i].k -= n;rq[++nr] = q[i];}}}//removefor(int i=ql;i<=qr;i++){if(q[i].op != 2){if(q[i].x <= mid) change(q[i].y, -q[i].op);}}for(int i=1;i<=nl;i++) q[ql+i-1] = lq[i];for(int i=1;i<=nr;i++) q[ql+nl+i-1] = rq[i];solve(vl, mid, ql, ql+nl-1);solve(mid+1, vr, ql+nl, qr);
}int main(){scanf("%d%d", &N, &M);int NN = 0, Q = 0; int x,l,r,k;for(int i=1;i<=N;++i){scanf("%d", &a[i]);q[++NN] = Node(1,a[i],i);}char op[5];for(int i=1;i<=M;i++){scanf("%s", op);if(op[0]=='Q'){scanf("%d%d%d", &l, &r, &k);q[++NN] = Node(2,l,r,k,++Q);} else{scanf("%d%d", &l, &x);q[++NN] = Node(-1,a[l],l);q[++NN] = Node(+1,x,l);a[l] = x;}}solve(-1e9,1e9,1,NN);for(int i=1;i<=Q;i++){printf("%d\n", ANS[i]);}return 0;
}