<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【學習筆記】整體二分

      一、簡述

      叫簡述是因為不知道該叫啥。

      整體二分是一種基于值域的分治算法,一般面對多次可二分的詢問時就可以整體二分。有時帶修改的問題也可以整體二分,但顯然它難以強制在線。

      整體二分的精髓在于對于一堆問題只 check 一次,從而節省相當多的時間。

      二、例題

      1.Luogu P3834 【模板】可持久化線段樹 2

      考慮如何高效地確定一些詢問的答案與當前 \(mid\) 的關系。

      考慮樹狀數組,將 \([l,mid]\) 中的數全都插入到對應的位置上。于是對于每個詢問,就可以用樹狀數組來求出詢問區間中 \([l,mid]\) 的數量。于是就好做了。時間復雜度 \(O(n\log^2n)\),需要離散化。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      using namespace std;
      namespace asbt{
      const int maxn=2e5+5;
      //int cnt;
      int n,m,a[maxn],lsh[maxn],tot,ans[maxn];
      struct{
      	int tr[maxn];
      	il int lowbit(int x){
      		return x&-x;
      	}
      	il void add(int p,int v){
      		for(;p<=n;p+=lowbit(p)){
      			tr[p]+=v;
      		}
      	}
      	il int query(int p){
      		int res=0;
      		for(;p;p-=lowbit(p)){
      			res+=tr[p];
      		}
      		return res;
      	}
      }F;
      struct node1{
      	int p,v;
      	node1(int p=0,int v=0):p(p),v(v){}
      };
      struct node2{
      	int l,r,k,id;
      	node2(int l=0,int r=0,int k=0,int id=0):l(l),r(r),k(k),id(id){}
      };
      il void solve(int l,int r,vector<node1> p,vector<node2> q){
      //	cerr<<l<<" "<<r<<" "<<p.size()<<" "<<q.size()<<"\n";
      	if(l==r){
      		for(node2 i:q){
      			ans[i.id]=lsh[l];
      		}
      		return ;
      	}
      	int mid=(l+r)>>1;
      	vector<node1> p1,p2;
      	for(node1 i:p){
      		if(i.v<=mid){
      			F.add(i.p,1);
      			p1.pb(i);
      		}
      		else{
      			p2.pb(i);
      		}
      	}
      	vector<node2> q1,q2;
      	for(node2 &i:q){
      //		cnt++;
      		int tmp=F.query(i.r)-F.query(i.l-1);
      		if(i.k<=tmp){
      			q1.pb(i);
      //			cerr<<"1 ";
      		}
      		else{
      			i.k-=tmp;
      			q2.pb(i);
      		}
      	}
      //	cerr<<"\n"<<q1.size()<<"\n";
      	for(node1 i:p){
      		if(i.v<=mid){
      			F.add(i.p,-1);
      		}
      	}
      	solve(l,mid,p1,q1);
      	solve(mid+1,r,p2,q2);
      }
      int main(){
      //	freopen("P3834_6.in","r",stdin);
      //	freopen("my.out","w",stdout);
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      		lsh[++tot]=a[i];
      	}
      	sort(lsh+1,lsh+tot+1);
      	tot=unique(lsh+1,lsh+tot+1)-lsh-1;
      	vector<node1> p;
      	for(int i=1;i<=n;i++){
      		a[i]=lower_bound(lsh+1,lsh+tot+1,a[i])-lsh;
      		p.pb(node1(i,a[i]));
      	}
      	vector<node2> q;
      	for(int i=1,l,r,k;i<=m;i++){
      		cin>>l>>r>>k;
      		q.pb(node2(l,r,k,i));
      	}
      	solve(1,tot,p,q);
      //	cerr<<cnt<<"\n";
      	for(int i=1;i<=m;i++){
      		cout<<ans[i]<<"\n";
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      2.[bzoj1901][Zju2112] Dynamic Rankings

      首先可以將更改操作改為一個刪除操作再加一個插入操作。將所有的操作和查詢存在一個操作序列中進行分治。對于當前的 \(mid\),如果一個修改操作要修改的數大于 \(mid\),那么它對左區間就不會有影響,直接放入右區間。否則就將貢獻加入樹狀數組,放入左區間即可。注意維持操作序列的時間順序。

      實際上是可以不離散化的,對時間復雜度的影響不大,但要注意必須特判掉空的操作序列區間,否則就會跑滿整個 dfs 樹,這樣的時間復雜度是無法承受的。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      const int maxn=1e5+5;
      int n,m,a[maxn],cnt,ans[maxn];
      struct node{
      	int typ,l,k,r,id;
      	node(int typ=0,int l=0,int k=0,int r=0,int id=0)
      		:typ(typ),l(l),k(k),r(r),id(id){}
      }b[maxn*3],hp[maxn*3];
      struct{
      	int tr[maxn];
      	il int lowbit(int x){
      		return x&-x;
      	}
      	il void add(int p,int v){
      		for(;p<=n;p+=lowbit(p)){
      			tr[p]+=v;
      		}
      	}
      	il int query(int p){
      		int res=0;
      		for(;p;p-=lowbit(p)){
      			res+=tr[p];
      		}
      		return res;
      	}
      }F;
      il void solve(int l,int r,int L,int R){
      	if(l>r){
      		return ;
      	}
      //	if(l!=10||r!=9){
      //		cout<<l<<" "<<r<<" "<<L<<" "<<R<<"\n";
      //	}
      	if(L==R){
      		for(int i=l;i<=r;i++){
      			ans[b[i].id]=L;
      		}
      		return ;
      	}
      	int pl=l,pr=r;
      	int mid=(L+R)>>1;
      	for(int i=l;i<=r;i++){
      		if(b[i].typ){
      			if(b[i].k<=mid){
      				F.add(b[i].l,b[i].typ);
      				hp[pl++]=b[i];
      			}
      			else{
      				hp[pr--]=b[i];
      			}
      		}
      		else{
      			int tmp=F.query(b[i].r)-F.query(b[i].l-1);
      			if(tmp>=b[i].k){
      				hp[pl++]=b[i];
      			}
      			else{
      				b[i].k-=tmp;
      				hp[pr--]=b[i];
      			}
      		}
      	}
      	for(int i=l;i<=r;i++){
      		if(b[i].typ&&b[i].k<=mid){
      			F.add(b[i].l,-b[i].typ);
      		}
      	}
      	for(int i=l;i<pl;i++){
      		b[i]=hp[i];
      	}
      	for(int i=pl,j=r;i<=r;i++,j--){
      		b[i]=hp[j];
      	}
      	solve(l,pr,L,mid);
      	solve(pl,r,mid+1,R);
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1;i<=n;i++){
      		cin>>a[i];
      		b[++cnt]=node(1,i,a[i]);
      	}
      	for(int i=1;i<=m;i++){
      		char typ;
      		cin>>typ;
      		if(typ=='Q'){
      			int l,r,k;
      			cin>>l>>r>>k;
      			b[++cnt]=node(0,l,k,r,i);
      		}
      		else{
      			int p,v;
      			cin>>p>>v;
      			b[++cnt]=node(-1,p,a[p]);
      			b[++cnt]=node(1,p,v);
      			a[p]=v;
      			ans[i]=-1;
      		}
      	}
      	solve(1,cnt,0,1e9);
      	for(int i=1;i<=m;i++){
      		if(~ans[i]){
      			cout<<ans[i]<<"\n";
      		}
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      3.[國家集訓隊] 矩陣乘法

      依然是區間第 \(k\) 大,只不過改成了矩陣,使用二維樹狀數組即可。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      namespace IO{
      	const int bufsz=1<<20;
      	char ibuf[bufsz],*p1=ibuf,*p2=ibuf;
      	#define getchar() (p1==p2&&(p2=(p1=ibuf)+fread(ibuf,1,bufsz,stdin),p1==p2)?EOF:*p1++)
      	il int read(){
      		char ch=getchar();
      		while(ch<'0'||ch>'9'){
      			ch=getchar();
      		}
      		int x=0;
      		while(ch>='0'&&ch<='9'){
      			x=(x<<1)+(x<<3)+(ch^48);
      			ch=getchar();
      		}
      		return x;
      	}
      	#undef getchar
      }
      using IO::read;
      const int maxn=6e4+5,maxm=3.2e5+5;
      int n,m,cnt,a[505][505],ans[maxn];
      struct{
      	int tr[505][505];
      	il int lowbit(int x){
      		return x&-x;
      	}
      	il void add(int x,int y,int v){
      		for(int i=x;i<=n;i+=lowbit(i)){
      			for(int j=y;j<=n;j+=lowbit(j)){
      				tr[i][j]+=v;
      			}
      		}
      	}
      	il int query(int x,int y){
      		int res=0;
      		for(int i=x;i;i-=lowbit(i)){
      			for(int j=y;j;j-=lowbit(j)){
      				res+=tr[i][j];
      			}
      		}
      		return res;
      	}
      }F;
      struct node{
      	int x1,y1,k,x2,y2,id;
      	node(int x1=0,int y1=0,int k=0,int x2=0,int y2=0,int id=0)
      		:x1(x1),y1(y1),x2(x2),y2(y2),k(k),id(id){}
      }b[maxm],hp[maxm];
      il void solve(int l,int r,int L,int R){
      	if(l>r){
      		return ;
      	}
      	if(L==R){
      		for(int i=l;i<=r;i++){
      			ans[b[i].id]=L;
      		}
      		return ;
      	}
      	int mid=(L+R)>>1,pl=l,pr=r;
      	for(int i=l;i<=r;i++){
      		if(b[i].id){
      			int x1=b[i].x1,y1=b[i].y1,x2=b[i].x2,y2=b[i].y2;
      			int tmp=F.query(x2,y2)-F.query(x1-1,y2)-F.query(x2,y1-1)+F.query(x1-1,y1-1);
      			if(tmp>=b[i].k){
      				hp[pl++]=b[i];
      			}
      			else{
      				b[i].k-=tmp;
      				hp[pr--]=b[i];
      			}
      		}
      		else{
      			if(b[i].k<=mid){
      				F.add(b[i].x1,b[i].y1,1);
      				hp[pl++]=b[i];
      			}
      			else{
      				hp[pr--]=b[i];
      			}
      		}
      	}
      	for(int i=l;i<=r;i++){
      		if(!b[i].id&&b[i].k<=mid){
      			F.add(b[i].x1,b[i].y1,-1);
      		}
      	}
      	for(int i=l;i<pl;i++){
      		b[i]=hp[i];
      	}
      	for(int i=pl,j=r;i<=r;i++,j--){
      		b[i]=hp[j];
      	}
      	solve(l,pr,L,mid);
      	solve(pl,r,mid+1,R);
      }
      int main(){
      	n=read(),m=read();
      	for(int i=1;i<=n;i++){
      		for(int j=1;j<=n;j++){
      			a[i][j]=read();
      			b[++cnt]=node(i,j,a[i][j]);
      		}
      	}
      	for(int i=1,x1,y1,x2,y2,k;i<=m;i++){
      		x1=read(),y1=read(),x2=read(),y2=read(),k=read();
      		b[++cnt]=node(x1,y1,k,x2,y2,i);
      	}
      	solve(1,cnt,0,1e9);
      	for(int i=1;i<=m;i++){
      		cout<<ans[i]<<"\n";
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      4.[THUPC2017] 天天愛射擊

      整體二分,將每個木板被擊碎的時間二分出來即可。注意有的木板可能根本無法擊穿。

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      using namespace std;
      namespace asbt{
      const int maxn=2e5+5;
      int n,m,a[maxn],ans[maxn];
      struct node{
      	int x1,x2,k;
      }b[maxn],hp[maxn];
      struct{
      	int tr[maxn];
      	il int lowbit(int x){
      		return x&-x;
      	}
      	il void add(int p,int v){
      		for(;p<=2e5;p+=lowbit(p)){
      			tr[p]+=v;
      		}
      	}
      	il int query(int p){
      		int res=0;
      		for(;p;p-=lowbit(p)){
      			res+=tr[p];
      		}
      		return res;
      	}
      }F;
      il 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(b[i].x1<=a[L]&&b[i].x2>=a[L]&&b[i].k==1){
      				ans[L]++;
      			}
      		}
      		return ;
      	}
      	int mid=(L+R)>>1,pl=l,pr=r;
      	for(int i=L;i<=mid;i++){
      		F.add(a[i],1);
      	}
      	for(int i=l;i<=r;i++){
      		int tmp=F.query(b[i].x2)-F.query(b[i].x1-1);
      		if(tmp>=b[i].k){
      			hp[pl++]=b[i];
      		}
      		else{
      			b[i].k-=tmp;
      			hp[pr--]=b[i];
      		}
      	}
      	for(int i=L;i<=mid;i++){
      		F.add(a[i],-1);
      	}
      	for(int i=l;i<pl;i++){
      		b[i]=hp[i];
      	}
      	for(int i=pl,j=r;i<=r;i++,j--){
      		b[i]=hp[j];
      	}
      	solve(l,pr,L,mid);
      	solve(pl,r,mid+1,R);
      }
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1;i<=n;i++){
      		cin>>b[i].x1>>b[i].x2>>b[i].k;
      	}
      	for(int i=1;i<=m;i++){
      		cin>>a[i];
      	}
      	solve(1,n,1,m);
      	for(int i=1;i<=m;i++){
      		cout<<ans[i]<<"\n";
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      

      5.「CTSC2018」混合果汁

      考慮對于單次詢問,顯然可以二分,每次將美味度大于等于 \(mid\) 的果汁放在一起按價格排序,貪心地計算能否在 \(g_j\) 的限制內買夠 \(L_j\) 的果汁。

      多次詢問可二分的問題,這提醒我們去做整體二分。但是有一個問題,我們無法在整體二分搜索樹上的每個節點都對大于等于 \(mid\) 的果汁進行排序計算,不然顯然會炸。有一個解決方案是,將一堆沒有交集的搜索樹節點放在一起計算,用線段樹維護按美味度排序后的某個后綴果汁集合。具體地,按照美味度倒著掃,對于每個美味度在 \([L,R]\) 的搜索樹節點,我們先將 \([mid+1,R]\) 的果汁加入線段樹,然后處理節點上的詢問,再將 \([L,mid]\) 的果汁加入線段樹。換言之,我們要按層遍歷搜索樹,并且每一層還要倒著遍歷!一個方案是用 std::vector 存儲當前層的搜索樹節點寫 bfs。時間復雜度 \(O((n+m)\log^2n)\)

      Code
      #include<bits/stdc++.h>
      #define ll long long
      #define il inline
      #define pb push_back
      using namespace std;
      namespace asbt{
      const int maxn=1e5+5;
      int n,m,lsh[maxn];
      ll ans[maxn];
      struct jui{
      	int d,p,l;
      }a[maxn];
      struct{
      	int id;
      	ll g,l;
      }b[maxn],hp[maxn];
      int rt,tot;
      struct{
      	int ls,rs,d,p,l;
      	ll smp,sml;
      }tr[maxn<<1];
      #define ls(id) tr[id].ls
      #define rs(id) tr[id].rs
      #define d(id) tr[id].d
      #define p(id) tr[id].p
      #define l(id) tr[id].l
      #define smp(id) tr[id].smp
      #define sml(id) tr[id].sml
      il void pushup(int id){
      	smp(id)=smp(ls(id))+smp(rs(id));
      	sml(id)=sml(ls(id))+sml(rs(id));
      }
      il void insert(int &id,int L,int R,int p,int d,int l){
      	if(!id){
      		id=++tot;
      		ls(id)=rs(id)=0;
      		d(id)=p(id)=l(id)=0;
      		smp(id)=sml(id)=0;
      	}
      	if(L==R){
      		smp(id)=lsh[p]*1ll*l;
      		sml(id)=l;
      		d(id)=d,p(id)=lsh[p],l(id)=l;
      		return ;
      	}
      	int mid=(L+R)>>1;
      	if(p<=mid){
      		insert(ls(id),L,mid,p,d,l);
      	}
      	else{
      		insert(rs(id),mid+1,R,p,d,l);
      	}
      	pushup(id);
      }
      il ll query(int id,int L,int R,ll g){
      	if(!id){
      		return 0;
      	}
      	if(L==R){
      		return min(g/p(id),l(id)*1ll);
      	}
      	int mid=(L+R)>>1;
      	if(smp(ls(id))>=g){
      		return query(ls(id),L,mid,g);
      	}
      	else{
      		return query(rs(id),mid+1,R,g-smp(ls(id)))+sml(ls(id));
      	}
      }
      #undef ls
      #undef rs
      #undef d
      #undef p
      #undef l
      #undef smp
      #undef sml
      struct node{
      	int L,R,l,r;
      	node(int L=0,int R=0,int l=0,int r=0):L(L),R(R),l(l),r(r){}
      };
      vector<node> q[2];
      int main(){
      	ios::sync_with_stdio(0),cin.tie(0);
      	cin>>n>>m;
      	for(int i=1;i<=n;i++){
      		cin>>a[i].d>>a[i].p>>a[i].l;
      	}
      	sort(a+1,a+n+1,[](const jui &x,const jui &y){return x.p<y.p;});
      	for(int i=1;i<=n;i++){
      		lsh[i]=a[i].p;
      		a[i].p=i;
      	}
      	sort(a+1,a+n+1,[](const jui &x,const jui &y){return x.d>y.d;});
      	for(int i=1;i<=m;i++){
      		cin>>b[i].g>>b[i].l;
      		b[i].id=i;
      	}
      	q[0].pb(node(1,1e5,1,m));
      	int cur=0;
      	while(q[cur].size()){
      		q[cur^1].clear();
      		int now=1;
      		rt=tot=0;
      		for(node x:q[cur]){
      			int L=x.L,R=x.R,l=x.l,r=x.r;
      //			cout<<L<<" "<<R<<":\n";
      //			for(int i=l;i<=r;i++){
      //				cout<<b[i].id<<" ";
      //			}
      //			puts("");
      			if(l>r){
      				continue;
      			}
      			if(L==R){
      				while(now<=n&&a[now].d>=L){
      					insert(rt,1,n,a[now].p,a[now].d,a[now].l);
      					now++;
      				}
      				for(int i=l;i<=r;i++){
      					if(query(rt,1,n,b[i].g)>=b[i].l){
      						ans[b[i].id]=L;
      					}
      					else{
      						ans[b[i].id]=-1;
      					}
      				}
      				continue;
      			}
      			int mid=(L+R)>>1;
      			while(now<=n&&a[now].d>mid){
      				insert(rt,1,n,a[now].p,a[now].d,a[now].l);
      				now++;
      			}
      			int pl=l,pr=r;
      			for(int i=l;i<=r;i++){
      				if(query(rt,1,n,b[i].g)>=b[i].l){
      					hp[pr--]=b[i];
      				}
      				else{
      					hp[pl++]=b[i];
      				}
      			}
      			for(int i=l;i<pl;i++){
      				b[i]=hp[i];
      			}
      			for(int i=pl;i<=r;i++){
      				b[i]=hp[i]; 
      			}
      			q[cur^1].pb(node(mid+1,R,pl,r));
      			q[cur^1].pb(node(L,mid,l,pr));
      			while(now<=n&&a[now].d>=L){
      				insert(rt,1,n,a[now].p,a[now].d,a[now].l);
      				now++;
      			}
      		}
      		cur^=1;
      	}
      	for(int i=1;i<=m;i++){
      		cout<<ans[i]<<"\n";
      	}
      	return 0;
      }
      }
      int main(){return asbt::main();}
      
      posted @ 2025-06-22 17:24  zhangxy__hp  閱讀(10)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 一区二区三区AV波多野结衣| 最新偷拍一区二区三区| 99久久免费精品国产色| 欧洲免费一区二区三区视频| 亚洲欧美v国产蜜芽tv| 国产综合色在线精品| 国色天香成人一区二区 | AV无码免费不卡在线观看| 最新偷拍一区二区三区| 美女人妻激情乱人伦| 久久天天躁夜夜躁一区| 欧美黑吊大战白妞| 国产乱人对白| 日韩高清在线亚洲专区国产| 国产av午夜精品福利| 国产福利社区一区二区| 俄罗斯老熟妇性爽xxxx| 日韩欧美视频一区二区三区| 九九热精品在线免费视频| 免费人成网站视频在线观看| 国产精品老年自拍视频| 国产v亚洲v天堂a无码| 亚洲无线看天堂av| 欧美熟妇性XXXX欧美熟人多毛| 久久精品不卡一区二区| 亚洲国内精品一区二区| 五月天天天综合精品无码| 亚洲av成人无码精品电影在线| 精品国产一区二区三区香| 欧美牲交a欧美牲交aⅴ一| 午夜在线欧美蜜桃| 国产在线播放专区av| 亚洲精品国产美女久久久| 亚洲精品揄拍自拍首页一| 欧美一本大道香蕉综合视频| 日韩永久永久永久黄色大片| 国产精品XXXX国产喷水| 日韩中文字幕高清有码| 国产中文99视频在线观看| 亚洲国产精品一区二区第一页| 少妇人妻偷人精品视频|