整体二分
Posted chdy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了整体二分相关的知识,希望对你有一定的参考价值。
关于整体二分的学习其实只是了解了普通二分之后自然就懂了整体二分了。没有很难但是基于整体二分是基于时间和值域的分治。
比CDQ要更强一点。因为可以在一些离线的题目当中代替树套树什么的。
同时也非常的好写 。至少代码好懂。
首先是值域上的二分 这个二分是分离不同的值毕竟不同的值在不同的区间之内。我们可以将其二分。但是单次二分也是可以得到整体的信息的不妨把所有的区间信息都一起处理了。这就是整体二分了。
对于当前值域L~R 一些操作在此区间是有价值的当前仅当区间第k大可以在此区间产生或者当前赋值<=mid 然后不断的进行二分 当然把操作也不断的进行二分 然后当L==R时区间的第k大自然就求出来了 注意这个同时还保证了时间的顺序。很正确。
关键是对值域进行二分。
求第k小的数字 直接进行整体二分即可主席树当然也行。
//#include<bits/stdc++.h> #include<iostream> #include<iomanip> #include<cmath> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<cstdlib> #include<cctype> #include<utility> #include<vector> #include<algorithm> #include<set> #include<map> #include<bitset> #define max(x,y) (x>y?x:y) #define up(p,i,n) for(int i=p;i<=n;++i) #define ll long long #define op(x) q[x].op #define x(i) q[i].x #define z(i) q[i].z #define y(i) q[i].y using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getc();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getc();} return x*f; } inline void put(int x) { x<0?putchar(‘-‘),x=-x:0; int num=0;char ch[50]; while(x)ch[++num]=x%10+‘0‘,x/=10; num==0?putchar(‘0‘):0; while(num)putchar(ch[num--]); putchar(‘ ‘);return; } const int MAXN=100002,INF=1000000000; int n,m,t; int c[MAXN],ans[MAXN]; struct wy { int op; int x,y,z; }q[MAXN<<1],lq[MAXN<<1],rq[MAXN<<1]; inline int ask(int x) { int cnt=0; for(;x;x-=x&(-x))cnt+=c[x]; return cnt; } inline void change(int x,int y) { for(;x<=n;x+=x&(-x))c[x]+=y; } inline void solve(int L,int R,int l,int r) { if(l>r)return; if(L==R) { for(int i=l;i<=r;++i)if(op(i))ans[op(i)]=L; return; } int mid=(L+R)>>1; int lt=0,rt=0; for(int i=l;i<=r;++i) { if(op(i)) { int cnt=ask(y(i))-ask(x(i)-1); if(cnt>=z(i))lq[++lt]=q[i]; else z(i)-=cnt,rq[++rt]=q[i]; } else { if(y(i)<=mid)change(q[i].x,1),lq[++lt]=q[i]; else rq[++rt]=q[i]; } } for(int i=l;i<=r;++i) { if(op(i))break; if(y(i)<=mid)change(q[i].x,-1); } for(int i=0;i<lt;++i)q[l+i]=lq[i+1]; for(int i=0;i<rt;++i)q[l+lt+i]=rq[i+1]; solve(L,mid,l,l+lt-1); solve(mid+1,R,l+lt,r); return; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=n;++i) { int x; x=read(); op(++t)=0;q[t].x=i;y(t)=x; } for(int i=1;i<=m;++i) { int x,y,k; x=read();y=read();k=read(); op(++t)=i;q[t].x=x;q[t].y=y;z(t)=k; } solve(-INF,INF,1,t); for(int i=1;i<=m;++i)put(ans[i]); return 0; }
我会树状数组套主席树貌似不太好写 我感觉比较ex。
这个直接整体二分,删除操作直接跟在后面即可 复杂度没变相当的优秀。
//#include<bits/stdc++.h> #include<iostream> #include<iomanip> #include<cmath> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<cstdlib> #include<cctype> #include<utility> #include<vector> #include<algorithm> #include<set> #include<map> #include<bitset> #define max(x,y) (x>y?x:y) #define up(p,i,n) for(int i=p;i<=n;++i) #define ll long long #define op(x) q[x].op #define x(i) q[i].x #define z(i) q[i].z #define y(i) q[i].y #define k(i) q[i].k using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } inline void put(int x) { x<0?putchar(‘-‘),x=-x:0; int num=0;char ch[50]; while(x)ch[++num]=x%10+‘0‘,x/=10; num==0?putchar(‘0‘):0; while(num)putchar(ch[num--]); putchar(‘ ‘);return; } const int MAXN=100002,INF=1000000000; int n,m,t,top; int c[MAXN],ans[MAXN],b[MAXN],a[MAXN]; char w[2]; struct wy { int op; int x,y,z,k; }q[MAXN<<2],lq[MAXN<<2],rq[MAXN<<2]; inline int ask(int x) { int cnt=0; for(;x;x-=x&(-x))cnt+=c[x]; return cnt; } inline void change(int x,int y) { for(;x<=n;x+=x&(-x))c[x]+=y; } inline void solve(int L,int R,int l,int r) { if(l>r)return; if(L==R) { for(int i=l;i<=r;++i)if(op(i))ans[op(i)]=L; return; } int mid=(L+R)>>1; int lt=0,rt=0; for(int i=l;i<=r;++i) { if(op(i)) { int cnt=ask(y(i))-ask(x(i)-1); if(cnt>=z(i))lq[++lt]=q[i]; else z(i)-=cnt,rq[++rt]=q[i]; } else { if(y(i)<=mid)change(x(i),k(i)),lq[++lt]=q[i]; else rq[++rt]=q[i]; } } for(int i=l;i<=r;++i)if(op(i)==0&&y(i)<=mid)change(x(i),-k(i)); for(int i=1;i<=lt;++i)q[l+i-1]=lq[i]; for(int i=1;i<=rt;++i)q[l+lt+i-1]=rq[i]; solve(L,mid,l,l+lt-1); solve(mid+1,R,l+lt,r); return; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=n;++i) { b[i]=read(); op(++t)=0;q[t].x=i;y(t)=b[i];k(t)=1; } for(int i=1;i<=m;++i) { int x,y,k; scanf("%s",w+1); if(w[1]==‘Q‘) { x=read();y=read();k=read(); op(++t)=i;q[t].x=x;q[t].y=y;z(t)=k; a[++top]=i; } else { x=read();y=read(); op(++t)=0;q[t].x=x;y(t)=b[x];k(t)=-1; op(++t)=0;q[t].x=x;y(t)=y;k(t)=1; b[x]=y; } } solve(0,INF,1,t); for(int i=1;i<=top;++i)put(ans[a[i]]); return 0; }
好写啊。
第三道模板题目 这个主要是 修改不太好修改在树状数组上修改的话直接就是n^2logn的了再加上外面的logn直接当场GG
所谓区间修改肯定是线段树啊。可能是早上的线段树卡了我一上午 我的线段树水平又提高了这道题线段树一遍A.
//#include<bits/stdc++.h> #include<iostream> #include<iomanip> #include<cmath> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<cstdlib> #include<cctype> #include<utility> #include<vector> #include<algorithm> #include<set> #include<map> #include<bitset> #define max(x,y) (x>y?x:y) #define up(p,i,n) for(ll i=p;i<=n;++i) #define ll long long #define op(x) q[x].op #define x(i) q[i].x #define z(i) q[i].z #define y(i) q[i].y #define k(i) q[i].k #define l(i) t[i].l #define r(i) t[i].r #define add(i) t[i].add #define sum(i) t[i].sum using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } inline void put(ll x) { x<0?putchar(‘-‘),x=-x:0; ll num=0;char ch[50]; while(x)ch[++num]=x%10+‘0‘,x/=10; num==0?putchar(‘0‘):0; while(num)putchar(ch[num--]); putchar(‘ ‘);return; } const ll MAXN=100002,INF=50000; ll n,m,top; ll c[MAXN],ans[MAXN],b[MAXN]; char w[2]; struct wy { ll op; ll x,y,k; }q[MAXN<<2],ql[MAXN<<2],qr[MAXN<<2]; struct wy1 { ll l,r; ll add; ll sum; }t[MAXN<<2]; inline void build(ll p,ll l,ll r) { l(p)=l;r(p)=r; sum(p)=0;add(p)=0; if(l==r)return; ll mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); } inline void pushdown(ll p) { if(add(p)<0) { add(p<<1)+=add(p);add(p<<1|1)+=add(p); sum(p<<1)+=(r(p<<1)-l(p<<1)+1)*add(p); sum(p<<1|1)+=(r(p<<1|1)-l(p<<1|1)+1)*add(p); } else { add(p<<1)+=add(p); add(p<<1|1)+=add(p); sum(p<<1)+=(r(p<<1)-l(p<<1)+1)*add(p); sum(p<<1|1)+=(r(p<<1|1)-l(p<<1|1)+1)*add(p); } add(p)=0;return; } inline void change(ll p,ll l,ll r,ll k) { if(l<=l(p)&&r>=r(p)) { if(k==-1) { add(p)--; sum(p)-=(r(p)-l(p)+1); return; } sum(p)+=(r(p)-l(p)+1)*k; add(p)+=k; return; } if(add(p))pushdown(p); ll mid=(l(p)+r(p))>>1; if(l<=mid)change(p<<1,l,r,k); if(r>mid)change(p<<1|1,l,r,k); sum(p)=sum(p<<1)+sum(p<<1|1); return; } inline ll ask(ll p,ll l,ll r) { if(l<=l(p)&&r>=r(p))return sum(p); if(add(p))pushdown(p); ll cnt=0; ll mid=(l(p)+r(p))>>1; if(l<=mid)cnt+=ask(p<<1,l,r); if(r>mid)cnt+=ask(p<<1|1,l,r); return cnt; } inline void solve(ll L,ll R,ll l,ll r) { if(l>r)return; if(L==R) { for(ll i=l;i<=r;++i)ans[op(i)]=L; return; } ll lt=0,rt=0; ll mid=(L+R)>>1; for(ll i=l;i<=r;++i) { if(op(i)) { ll cnt=ask(1,x(i),y(i)); if(cnt>=k(i))qr[++rt]=q[i]; else k(i)-=cnt,ql[++lt]=q[i]; } else { if(k(i)>mid)change(1,x(i),y(i),1),qr[++rt]=q[i]; else ql[++lt]=q[i]; } } for(ll i=l;i<=r;++i)if(k(i)>mid&&op(i)==0)change(1,x(i),y(i),-1); for(ll i=1;i<=lt;++i)q[l+i-1]=ql[i]; for(ll i=1;i<=rt;++i)q[l+lt+i-1]=qr[i]; solve(L,mid,l,l+lt-1); solve(mid+1,R,l+lt,r); return; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(ll i=1;i<=m;++i) { ll p; p=read(); if(p==1)op(i)=0,x(i)=read(),y(i)=read(),k(i)=read(); else b[++top]=op(i)=i,x(i)=read(),y(i)=read(),k(i)=read(); } build(1,1,n); solve(-INF,INF,1,m); for(ll i=1;i<=top;++i)put(ans[b[i]]); return 0; }
改成二维的树状数组快速数点即可。
注意空间要开够。细节别打错。
/************************************************************** Problem: 2738 User: chdy Language: C++ Result: Accepted Time:13556 ms Memory:249624 kb ****************************************************************/ //#include<bits/stdc++.h> #include<iostream> #include<iomanip> #include<cmath> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<cstdlib> #include<cctype> #include<utility> #include<vector> #include<algorithm> #include<set> #include<map> #include<bitset> #define up(p,i,n) for(int i=p;i<=n;++i) #define ll long long #define op(x) q[x].op #define x(i) q[i].x #define y(i) q[i].y #define s(i) q[i].s #define w(i) q[i].w #define k(i) q[i].k using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } inline void put(int x) { x<0?putchar(‘-‘),x=-x:0; int num=0;char ch[50]; while(x)ch[++num]=x%10+‘0‘,x/=10; num==0?putchar(‘0‘):0; while(num)putchar(ch[num--]); putchar(‘ ‘);return; } const int MAXN=3500000,maxn=60002; int n,m,t,top,num; int ans[maxn],c[502][502],b[502*502]; struct wy { int x,y,s,w; int k; int op; }q[MAXN],ql[MAXN],qr[MAXN]; inline void add(int x,int y,int z) { for(int i=x;i<=n;i+=i&(-i)) for(int j=y;j<=n;j+=j&(-j)) c[i][j]+=z; } inline int ask(int x,int y) { int cnt=0; for(int i=x;i;i-=i&(-i)) { for(int j=y;j;j-=j&(-j)) cnt+=c[i][j]; } return cnt; } inline void solve(int L,int R,int l,int r) { if(l>r)return; if(L==R) { for(int i=l;i<=r;++i) if(op(i))ans[op(i)]=L; return; } int lt=0,rt=0; int mid=(L+R)>>1; for(int i=l;i<=r;++i) { if(op(i)) { int cnt=ask(s(i),w(i))-ask(s(i),y(i)-1)-ask(x(i)-1,w(i))+ask(x(i)-1,y(i)-1); if(cnt>=k(i))ql[++lt]=q[i]; else k(i)-=cnt,qr[++rt]=q[i]; } else { if(s(i)<=mid)add(x(i),y(i),1),ql[++lt]=q[i]; else qr[++rt]=q[i]; } } for(int i=l;i<=r;++i) { //if(op(i))break; if(op(i)==0&&s(i)<=mid)add(x(i),y(i),-1); } for(int i=1;i<=lt;++i)q[l+i-1]=ql[i]; for(int i=1;i<=rt;++i)q[l+lt+i-1]=qr[i]; solve(L,mid,l,l+lt-1); solve(mid+1,R,l+lt,r); return; } inline void discrete() { sort(b+1,b+1+top); for(int i=1;i<=top;++i)if(b[i]!=b[i-1])b[++num]=b[i]; return; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) { op(++t)=0; x(t)=i;y(t)=j; s(t)=read();b[++top]=s(t); } } discrete(); top=0; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) { ++top;s(top)=lower_bound(b+1,b+1+num,s(top))-b; } for(int i=1;i<=m;++i) { op(++t)=i; x(t)=read();y(t)=read(); s(t)=read();w(t)=read(); k(t)=read(); } solve(1,num,1,t); for(int i=1;i<=m;++i)put(b[ans[i]]); return 0; }
明天期中考试 加油ヾ(?°∇°?)??
以上是关于整体二分的主要内容,如果未能解决你的问题,请参考以下文章