• 整体二分


    整体二分

    今天刚透彻了整体二分,写篇blog;
    由于整体二分比较难以口述,来道例题讲解
    静态区间第k小
    同时也是主席树模板题,可是主席树模板怎么能用主席树写呢
    往下看,不会主席树的也可以水过这道紫体题了;
    首先设A序列表示表示给定序列;
    所有询问的答案一定在MINA~MAXA之间;
    对MINA~MAXA进行二分答案;
    二分答案一个询问想必大家都会,单数这道题时间不允许;
    考虑对整体进行二分,对于所有询问二分;
    也就是对询问进行分类,考虑二分出的答案mid;
    用树状数组维护小于等于mid的个数;
    对于每个区间ask(r)-ask(l-1)可以知道在这个询问区间里小于等于mid的个数;
    就可以把所有询问分为两类,设num为l~r里小于等于mid的个数;
    第一类:num<=k 第二类num>k;
    考虑第一类询问的答案一定在L~mid之间;
    第二类询问的答案一定在mid+1~R之间;
    L,R表示当前的答案区间;
    那么就可以把询问分成两类在分别将行分治
    知道L==R为止,L就是答案;
    注意A序列也要分开;
    考虑对于第一类询问,A序列中>mid的值对这些区间没有影响
    所以可以直接舍弃;
    对于第二类询问,它们的答案一定在mid+1~r之间
    所以只考虑>mid的值;
    例题

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=2e5+7;
    const int inf=1e9; 
    struct node{
    	int op,x,y,z;
    }q[N<<1],ql[N<<1],qr[N<<1];
    int n,m,cnt;
    int ans[N],t[N];
    int lowbit(int x){
    	return x&-x;
    }
    void change(int x,int val){
    	for(;x<=N-7;x+=lowbit(x)){
    		t[x]+=val;
    	}
    }
    int ask(int x){
    	int res=0;
    	for(;x;x-=lowbit(x)){
    		res+=t[x];
    	}
    	return res;
    }
    void work(int L,int R,int l,int r){
    	if(l>r) return;
    	if(L==R){
    		for(int i=l;i<=r;i++){
    			if(q[i].op>0) ans[q[i].op]=L;
    		}
    		return;
    	}
    	int mid=(L+R)>>1;
    	int tl=0,tr=0;
    	for(int i=l;i<=r;i++){
    		if(q[i].op==0){//属于A序列
    			if(q[i].y<=mid) change(q[i].x,1),ql[++tl]=q[i];
    			else qr[++tr]=q[i];
    		} else {//属于询问区间
    			int tt=ask(q[i].y)-ask(q[i].x-1);
    			if(tt>=q[i].z) ql[++tl]=q[i];
    			else {
    				q[i].z-=tt;//减去tt;
    				qr[++tr]=q[i];
    			}
     		}
    	}
    	for(int i=r;i>=l;i--){
    		if(q[i].op==0&&q[i].y<=mid) change(q[i].x,-1);//清空树状数组;
    	}
    	for(int i=1;i<=tl;i++) q[l+i-1]=ql[i];
    	for(int i=1;i<=tr;i++) q[l+tl+i-1]=qr[i];
    	work(L,mid,l,l+tl-1);
    	work(mid+1,R,l+tl,r);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&q[++cnt].y);
    		q[cnt].op=0;q[cnt].x=i;//op分类
    	}
    	for(int i=1;i<=m;i++){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		q[++cnt].x=x;
    		q[cnt].y=y;
    		q[cnt].z=z;
    		q[cnt].op=i;
    	}
    	work(-inf,inf,1,cnt);
    	for(int i=1;i<=m;i++) cout<<ans[i]<<"
    ";
    }
    
  • 相关阅读:
    Atitit 索引技术--位图索引
    Atitit View事件分发机制
    Atitit 代码复用的理解attilax总结
    Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折
    Atitit事件代理机制原理 基于css class的事件代理
    Atitit  图像处理Depixelizing Pixel Art像素风格画的矢量化
    Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析
    Atitit常见的标准化组织与规范数量jcp ecma iso
    Atitit sql计划任务与查询优化器--统计信息模块
    Atitti 存储引擎支持的国内点与特性attilax总结
  • 原文地址:https://www.cnblogs.com/Aswert/p/13623171.html
Copyright © 2020-2023  润新知