整体二分小结
整体二分
整体二分简单来说就是把所有修改和询问一起二分
要求询问满足二分性,询问相互独立
思想就是每次二分到一个答案,将询问划分到左右两个区间
那么以什么作为划分依据呢?
取决于操作对左右区间的贡献,如果有贡献就放到左区间 ,否则放入右区间,并将这次贡献的权值减去
同时,用树状数组或线段树来维护贡献值
注意每次操作完后要将修改还原
例题:
1. 区间第K小
静态 :luogu P3834
Code :
// luogu-judger-enable-o2 #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> #include<stack> #include<queue> using namespace std; typedef long long ll; const int maxn = 500010; const int INF = 1e9+7; int n,m,cnt; int c[maxn]; int ans[maxn]; struct Node{ int x,y,k,pos,qr; }q[maxn],q1[maxn],q2[maxn]; void add(int x,int k){ for(int i=x;i<=n;i+=i&(-i)) c[i]+=k; } int sum(int x){ int res=0; for(int i=x;i>0;i-=i&(-i)) res+=c[i]; return res; } void solve(int l,int r,int x,int y){ if(l>r || x>y) return; if(l==r) { for(int i=x;i<=y;i++) if(q[i].qr) ans[q[i].pos]=l; return; } int mid=(l+r)>>1, cnt1=0, cnt2=0; for(int i=x;i<=y;i++){ if(q[i].qr){ int tmp=sum(q[i].y)-sum(q[i].x-1); if(tmp>=q[i].k) q1[++cnt1]=q[i]; else q[i].k-=tmp,q2[++cnt2]=q[i]; }else{ if(q[i].x<=mid) q1[++cnt1]=q[i],add(q[i].pos,q[i].y); else q2[++cnt2]=q[i]; } } for(int i=1;i<=cnt1;i++) if(!q1[i].qr) add(q1[i].pos,-q1[i].y); for(int i=1;i<=cnt1;i++) q[x+i-1]=q1[i]; for(int i=1;i<=cnt2;i++) q[x+cnt1+i-1]=q2[i]; solve(l,mid,x,x+cnt1-1); solve(mid+1,r,x+cnt1,y); } int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } int main(){ n=read(),m=read(); int x,y,k; for(int i=1;i<=n;i++){ x=read(); q[++cnt]=(Node){x,1,0,i,0}; } for(int i=1;i<=m;i++){ x=read(),y=read(),k=read(); q[++cnt]=(Node){x,y,k,i,1}; } solve(-INF,INF,1,cnt); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
动态 :dynamic ranking
Code :
(留坑待填)
2. POI MET-Meteors
询问是 n 个国家的陨石数量,注意可能爆long long ,如果答案已经超过询问的值要跳出。
Code :
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> #include<stack> #include<queue> #include<vector> using namespace std; typedef long long ll; const int maxn = 300030; const ll INF = 1e9+7; int n,m,K,cnt; ll ans[maxn],c[maxn]; struct C{ int l,r; ll w; }e[maxn]; struct Q{ int id; ll k; }q[maxn],q1[maxn],q2[maxn]; vector<int> ar[maxn]; void add(int x,ll v){ for(int i=x;i<=m;i+=i&(-i)) c[i]+=v; } ll sum(int x){ ll res=0; for(int i=x;i>0;i-=i&(-i)) res+=c[i]; return res; } void mdf(int u,int f){ if(e[u].l>e[u].r) add(1,f*e[u].w); add(e[u].l,f*e[u].w); add(e[u].r+1,-f*e[u].w); } void solve(int l,int r,int x,int y){ if(x>y) return; if(l==r){ for(int i=x;i<=y;i++) ans[q[i].id]=l; return; } int mid=(l+r)>>1,cnt1=0,cnt2=0; for(int i=l;i<=mid;i++) mdf(i,1); ll tot; for(int i=x;i<=y;i++){ tot=0; for(int j=0;j<ar[q[i].id].size();j++){ tot+=sum(ar[q[i].id][j]); if(tot>=q[i].k) break; } if(tot>=q[i].k) q1[++cnt1]=q[i]; else { q[i].k-=tot; q2[++cnt2]=q[i]; } } for(int i=l;i<=mid;i++) mdf(i,-1); for(int i=1;i<=cnt1;i++) q[i+x-1]=q1[i]; for(int i=1;i<=cnt2;i++) q[i+x+cnt1-1]=q2[i]; solve(l,mid,x,x+cnt1-1); solve(mid+1,r,x+cnt1,y); } ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } int main(){ n=read(),m=read(); for(int i=1;i<=m;i++) ar[read()].push_back(i); for(int i=1;i<=n;i++){ q[i].k=read(); q[i].id=i; } K=read(); for(int i=1;i<=K;i++) e[i].l=read(),e[i].r=read(),e[i].w=read(); ++K; e[K]=(C){1,m,INF}; solve(1,K,1,n); for(int i=1;i<=n;i++) { if(ans[i]==K) printf("NIE\n"); else printf("%lld\n",ans[i]); } return 0; }