整體二分入門及模板
阿新 • • 發佈:2018-11-22
這已經是繼學歸併樹,主席樹以來第三次寫這個題了,整體二分就是每次二分一個答案m,根據當前的問題,如果在某個問題的區間內,小於等於m的數超過了這個問題的k,那麼顯然這個問題的答案小於m,因此把這個問題劃分到左邊,否則劃分到右邊,然後繼續二分,直到當前左區間等於右區間,那麼左區間 l 就是當前存在的問題的解,記錄下來即可。
#include<cstdio> #include<algorithm> #define low(x) x&-x using namespace std; const int maxn=1e5+10,inf=1<<30; struct node { int x,id; bool operator<(const node&t)const { return x<t.x; } }a[maxn]; struct Q { int x,y,k,id; }qu[maxn],tmp[maxn]; int c[maxn],ans[maxn],n,o; void add(int x,int v) { while(x<=n) c[x]+=v,x+=low(x); } int sum(int x) { int res=0; while(x) res+=c[x],x-=low(x); return res; } void solve(int l,int r,int ql,int qr) { int p=ql,q=qr,m=(l+r)/2; if(l==r) { for(int i=ql;i<=qr;i++)ans[qu[i].id]=l; return; } while((a[o+1].x<=m&&o<n))++o,add(a[o].id,1); while(o&&a[o].x>m)add(a[o].id,-1),--o; for(int i=ql;i<=qr;i++) { int res=sum(qu[i].y)-sum(qu[i].x-1); if(res>=qu[i].k)tmp[p++]=qu[i]; else tmp[q--]=qu[i]; } reverse(tmp+q+1,tmp+qr+1); for(int i=ql;i<=qr;i++)qu[i]=tmp[i]; if(p>ql)solve(l,m,ql,p-1); if(q<qr)solve(m+1,r,q+1,qr); } int main() { int T,m; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) a[i].id=i,c[i]=0,scanf("%d",&a[i].x); sort(a+1,a+1+n); for(int i=1;i<=m;i++) qu[i].id=i,scanf("%d%d%d",&qu[i].x,&qu[i].y,&qu[i].k); o=0; solve(-inf,inf,1,m); for(int i=1;i<=m;i++)printf("%d\n",ans[i]); } }