• BZOJ4604:The kth maximum number


    浅谈离线分治算法:https://www.cnblogs.com/AKMer/p/10415556.html

    题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=4604

    整体二分套(CDQ)分治,判断一个询问的答案是否大于等于(mid)的时候用(cdq)分治数点就行了。

    注意(x)相同的时候先修改。

    时间复杂度:(O(nlog^3n))

    空间复杂度:(O(n))

    代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define low(i) ((i)&(-(i)))
    
    const int maxn=5e5+5;
    
    bool bo[maxn];
    int ans[maxn];
    int n,Q,ans_cnt,maxv;
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    struct query {
    	int id,x1,x2,y1,y2,k;
    
    	query() {}
    
    	query(int _id,int _x1,int _y1,int _x2,int _y2,int _k) {
    		id=_id,x1=_x1,x2=_x2,y1=_y1,y2=_y2,k=_k;
    	}
    
    	bool operator<(const query &a)const {
    		if(x1==a.x1)return id<a.id;
    		return x1<a.x1;
    	}
    }p[maxn],tmp[maxn<<2];
    
    struct tree_array {
    	int c[maxn];
    
    	void add(int pos,int v) {
    		for(int i=pos;i<=n;i+=low(i))
    			c[i]+=v;
    	}
    
    	int query(int pos) {
    		int res=0;
    		for(int i=pos;i;i-=low(i))
    			res+=c[i];
    		return res;
    	}
    }T;
    
    void cdq_solve(int l,int r) {
    	if(l>=r)return;
    	int mid=(l+r)>>1;
    	cdq_solve(l,mid),cdq_solve(mid+1,r);
    	sort(tmp+l,tmp+r+1);
    	for(int i=l;i<=r;i++)
    		if(!tmp[i].id&&tmp[i].y2<=mid)T.add(tmp[i].y1,1);
    		else if(tmp[i].id&&tmp[i].y2>mid)
    			ans[tmp[i].id]+=tmp[i].x2*T.query(tmp[i].y1);
    	for(int i=l;i<=r;i++)
    		if(!tmp[i].id&&tmp[i].y2<=mid)T.add(tmp[i].y1,-1);
    }
    
    void solve(int l,int r,int st,int ed) {
    	if(ed<st)return;
    	if(l==r) {
    		for(int i=st;i<=ed;i++)
    			ans[p[i].id]=l;
    		return;
    	}
    	int mid=(l+r)>>1;
    	int cnt=0;
    	for(int i=st;i<=ed;i++)
    		if(!p[i].id) {
    			if(p[i].k>mid)
    				tmp[++cnt]=p[i],tmp[cnt].y2=cnt;
    		}
    		else {
    			ans[p[i].id]=0;
    			++cnt,tmp[cnt]=query(p[i].id,p[i].x2,p[i].y2,1,cnt,0);
    			++cnt,tmp[cnt]=query(p[i].id,p[i].x2,p[i].y1-1,-1,cnt,0);
    			++cnt,tmp[cnt]=query(p[i].id,p[i].x1-1,p[i].y2,-1,cnt,0);
    			++cnt,tmp[cnt]=query(p[i].id,p[i].x1-1,p[i].y1-1,1,cnt,0);
    		}
    	cdq_solve(1,cnt),cnt=0;
    	for(int i=st;i<=ed;i++)
    		if(!p[i].id) {
    			if(p[i].k>mid)bo[i]=0;
    			else bo[i]=1,cnt++;
    		}
    		else {
    			if(ans[p[i].id]>=p[i].k)bo[i]=0;
    			else bo[i]=1,cnt++,p[i].k-=ans[p[i].id];
    		}
    	int ED=st,ST=st+cnt;
    	for(int i=st;i<=ed;i++)
    		if(bo[i])tmp[ED++]=p[i];
    		else tmp[ST++]=p[i];
    	for(int i=st;i<=ed;i++)p[i]=tmp[i];
    	solve(l,mid,st,ED-1),solve(mid+1,r,ED,ed);
    }
    
    int main() {
    	n=read(),Q=read();
    	for(int i=1;i<=Q;i++) {
    		int opt=read();
    		if(opt==1) {
    			int x=read(),y=read(),k=read();
    			p[i]=query(0,x,y,0,0,k),maxv=max(maxv,k);
    		}
    		else {
    			int x1=read(),y1=read(),x2=read(),y2=read(),k=read();
    			p[i]=query(++ans_cnt,x1,y1,x2,y2,k);
    		}
    	}
    	solve(0,maxv,1,Q);
    	for(int i=1;i<=ans_cnt;i++)
    		if(ans[i])printf("%d
    ",ans[i]);
    		else puts("NAIVE!ORZzyz.");
    	return 0;
    }
    
  • 相关阅读:
    Java集合和数组的区别
    二分法查找
    功能模块划分的原则及方法
    CentOS 6.5 开机启动指定服务
    CentOS 6.5配置mysql
    CentOS 6.5安装Tcpreplay
    CentOS6.5 常用命令
    CentOS6.5 安装ntopng-1.2.0
    【转】CentOS安装PF_RING(虚拟机)
    CentOS查询 杀死进程
  • 原文地址:https://www.cnblogs.com/AKMer/p/10431174.html
Copyright © 2020-2023  润新知